在 PHPUnit 中使用 expectException 和间谍
Using expectException and a spy in PHPUnit
我正在使用 PHP单位 ~5.2
和 PHP ~7.0.0
。
我有一个 class 包装存储库,捕获它抛出的异常,调用记录器,然后重新抛出异常。
public function storeDonation( Donation $donation ) {
try {
$this->repository->storeDonation( $donation );
}
catch ( StoreDonationException $ex ) {
$this->logger->log( $this->logLevel, $ex->getMessage(), [ 'exception' => $ex ] );
throw $ex;
}
}
在我的测试中,我为记录器创建了一个间谍,所以我可以看到对记录函数进行了哪些调用。这个间谍是一个专用的测试替身,不是通过 PHP 单元模拟 API 创建的。当使用 PHPUnit 模拟 API 时,我 运行 遇到的问题不会发生,但是我在这里不是询问对该决定的反馈。
我 运行 遇到问题的测试方法有一些设置代码,然后它调用了 PHPUnits expectException
(以前是 setExpectedException
在 PHPUnit 5.1 及更早版本中),然后调用生产方法,最后从间谍获取日志调用以断言正确的调用。
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!');
}
我正在使用 PHP单位 ~5.2
和 PHP ~7.0.0
。
我有一个 class 包装存储库,捕获它抛出的异常,调用记录器,然后重新抛出异常。
public function storeDonation( Donation $donation ) {
try {
$this->repository->storeDonation( $donation );
}
catch ( StoreDonationException $ex ) {
$this->logger->log( $this->logLevel, $ex->getMessage(), [ 'exception' => $ex ] );
throw $ex;
}
}
在我的测试中,我为记录器创建了一个间谍,所以我可以看到对记录函数进行了哪些调用。这个间谍是一个专用的测试替身,不是通过 PHP 单元模拟 API 创建的。当使用 PHPUnit 模拟 API 时,我 运行 遇到的问题不会发生,但是我在这里不是询问对该决定的反馈。
我 运行 遇到问题的测试方法有一些设置代码,然后它调用了 PHPUnits expectException
(以前是 setExpectedException
在 PHPUnit 5.1 及更早版本中),然后调用生产方法,最后从间谍获取日志调用以断言正确的调用。
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!');
}