在PHPUnit中使用expectException和一个spy



我使用的是PHPUnit ~5.2和PHP ~7.0.0

我有一个类,它封装存储库,捕获它抛出的异常,调用记录器,然后重新抛出异常。

public function storeDonation( Donation $donation ) {
    try {
        $this->repository->storeDonation( $donation );
    }
    catch ( StoreDonationException $ex ) {
        $this->logger->log( $this->logLevel, $ex->getMessage(), [ 'exception' => $ex ] );
        throw $ex;
    }
}

在我的测试中,我为记录器创建了一个间谍,这样我就可以看到对日志记录函数进行了哪些调用。这个间谍是一个专门的测试替身,不是通过PHPUnit嘲笑API创建的。当使用PHPUnit嘲弄API时,我遇到的问题不会发生,但我在这里并没有询问对该决定的反馈。

我遇到问题的测试方法有一些设置代码,然后它调用PHPUnits expectException(在PHPUnit5.1及更早版本中曾是setExpectedException),然后调用生产方法,最后从间谍那里获得日志记录调用,以断言正确的调用。

public function testWhenGetDonationByIdThrowException_itIsLoggedAndThrown() {
    $logger = new LoggerSpy();
    $loggingRepo = new LoggingDonationRepository(
        $this->newThrowingRepository(),
        $logger
    );
    $this->expectException( GetDonationException::class );
    $loggingRepo->getDonationById( 1337 );
    $this->assertEquals(
        [
            [
                LogLevel::CRITICAL,
                self::GET_DONATION_BY_ID_EXCEPTION_MESSAGE,
                $this->newGetDonationException()
            ]
        ],
        $logger->getLogCalls()
    );
}

问题是,当抛出异常时,PHPUnit会捕获它并计算expectException,之后我的测试方法将无法继续执行。因此,使用我的间谍的断言从未运行过。

我正在寻找解决这个问题的方法。我已经考虑过将该方法拆分为一个包含expectException部分的方法,另一个包含用于生产代码调用的伪try-catch和用于间谍的断言。有什么更好的方法的建议吗?

当抛出异常时,以下所有代码都会中断,直到出现catch语句。这也适用于你的测试方法。

PHPUnit总是捕捉异常,这样它就可以记录它们,通过使用expectedException,您只需要告诉它处理抛出的有点不同的异常。

因此,如果您想在抛出异常后进行其他检查,则需要编写自己的try catch块。下面是一个如何做到这一点的例子:

public function testWhenGetDonationByIdThrowException_itIsLoggedAndThrown() {
    $logger = new LoggerSpy();
    $loggingRepo = new LoggingDonationRepository(
        $this->newThrowingRepository(),
        $logger
    );
    try {
        $loggingRepo->getDonationById( 1337 );
    } catch (GetDonationException $e) {
        $this->assertEquals(
            [[
                LogLevel::CRITICAL,
                self::GET_DONATION_BY_ID_EXCEPTION_MESSAGE,
                $this->newGetDonationException()
            ]],
            $loger->getLogCalls()
        );
        return;
    }
    $this->fail('Expected exception wasn't thrown!');
}

最新更新