使用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);
}
答案 0 :(得分:21)
我认为这是单元测试中非常常见的情况。我在这种情况下使用的方法是使用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);
}
}
答案 1 :(得分:19)
由于异常是程序流程中的重大事件,因此在单个测试中测试多个事件是有问题的。
最简单的方法是简单地将其拆分为两个测试 - 第一个需要一个异常才能通过,第二个只是简单地运行,并且会失败它会抛出一个。如果你想要的话,你可以在第二个中添加一些其他的测试(可能确认一个返回值),但根据它的命名,我倾向于确保它仍然只做了一件必不可少的事情。
/**
* @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
}
答案 2 :(得分:8)
稍微清洁的代码(但我仍然建议拆分你的测试:
try {
foo(-1);
$this->fail('No exception thrown');
} catch (Exception $e) {}
答案 3 :(得分:1)
这对我没有意义。
我猜你试图用一个测试用例测试多个不同的东西,这是不好的做法。
当foo()
抛出预期的异常时,测试用例成功,bar()
将无法运行。
只需创建两个单独的测试用例,这比在第二个列表中生成的代码要少得多。
或解释为什么在bar()
因异常而失败后运行foo()
会导致异常,这也是有意义的。
答案 4 :(得分:0)
扩展@ 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) {
}
}
}