[英]How do I test for multiple exceptions with PHPUnit?
使用 PHPUnit 測試異常時,要求每個語句或斷言都必須拋出異常才能使測試通過的最佳方法是什么?
我基本上想做這樣的事情:
public function testExceptions()
{
$this->setExpectedException('Exception');
foo(-1); //throws exception
foo(1); //does not throw exception
}
//Test will fail because foo(1) did not throw an exception
我想出了以下方法,它可以完成工作,但在 IMO 中非常丑陋。
public function testExceptions()
{
try {
foo(-1);
} catch (Exception $e) {
$hit = true;
}
if (!isset($hit))
$this->fail('No exception thrown');
unset($hit);
try {
foo(1);
} catch (Exception $e) {
$hit = true;
}
if (!isset($hit))
$this->fail('No exception thrown');
unset($hit);
}
我認為這是單元測試中非常常見的情況。 我在這種情況下使用的方法是使用phpunit dataProviders 。 一切都按預期工作,測試代碼變得更加清晰簡潔。
class MyTest extends PHPUnit\Framework\TestCase
{
public function badValues(): array
{
return [
[-1],
[1]
];
}
/**
* @dataProvider badValues
* @expectedException Exception
*/
public function testFoo($badValue): void
{
foo($badValue);
}
}
由於異常是程序流程中的重大事件,因此在單個測試中測試多個事件是有問題的。
最簡單的方法是簡單地將它分成兩個測試 - 第一個需要一個異常才能通過,第二個只是簡單地運行,並且會失敗它它會拋出一個。 如果你想要的話,你可以在第二個中添加一些其他的測試(確認一個返回值),但是根據它的命名,我傾向於確保它仍然只做了一件必不可少的事情。
/**
* @expectedException Exception
*/
public function testBadFooThrowsException()
{
// optional, can also do it from the '@expectedException x'
//$this->setExpectedException('Exception');
foo(-1); //throws exception -- good.
}
public function testFooDoesNotThrowException()
{
foo(1); //does not throw exception
}
稍微清潔的代碼(但我仍然建議拆分你的測試:
try {
foo(-1);
$this->fail('No exception thrown');
} catch (Exception $e) {}
這對我來說沒有意義。
我猜你試圖用一個測試用例測試多個單獨的東西,這是不好的做法。
當foo()
拋出預期的異常時,測試用例成功, bar()
將不會運行。
只需創建兩個單獨的測試用例,這比在第二個列表中生成的代碼要少得多。
或解釋為什么在foo()
失敗並出現異常后運行bar()
有意義的,因為它也會拋出異常。
擴展@ dave1010的答案,這就是我解決這個問題的方法。 這允許您在一次測試中保持所有這些“斷言”干凈整潔。 您只需定義一個應該使測試失敗的變量數組,然后遍歷每個變量並查看是否引發了異常。 如果任何失敗(沒有拋出異常),則測試失敗,否則測試通過。
<?php
public function testSetInvalidVariableType()
{
$invalid_vars = array(
'', // Strings
array(), // Arrays
true, // Booleans
1, // Integers
new \StdClass // Objects
);
foreach ($invalid_vars as $var) {
try {
$object->method($var);
$this->fail('No exception thrown for variable type "' . gettype($var) . '".');
} catch (\Exception $expected) {
}
}
}
您可以在測試用例 class 中創建這樣的方法
public function assertThrowsException(\Closure $closure, string $exception)
{
try {
$closure();
$this->fail("Closure doesn't throw any exception");
} catch (PHPUnit\Framework\AssertionFailedError $e) {
throw $e;
} catch (\Exception $e) {
$this->assertInstanceOf($exception, $e, "Wrong exception type");
}
}
然后像這樣稱呼它
$this->assertThrowsException(function() {
foo(1);
}, SomeException::class);
$this->assertThrowsException(function() {
foo(-1);
}, AnotherException::class);
這里可能需要一些改進,可能會有一些邊緣情況,但我認為這可能會讓你走很長一段路。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.