为什么PHPUnit不执行这段代码中的最后一个异常Assert?
public function testConfigOverriding()
{
$this->dependencyContainer = new DependencyContainer(__DIR__ . "/../../Resources/valid_json.json");
$this->assertEquals('overriden', $this->dependencyContainer->getConfig('shell_commander')['pygmentize_command']);
$unexisting = "unexisting_file";
$this->setExpectedException('Exception', "Configuration file at path \"$unexisting\" doesn't exist.");
$this->dependencyContainer = new DependencyContainer($unexisting);
$invalid = __DIR . "/../../Resources/invalid_json.json";
$this->setExpectedException('Exception', "Configuration JSON file provided is not valid.");
$this->dependencyContainer = new DependencyContainer($invalid);
}
所以基本上它测试是否抛出了"unexsisting_file"异常,但完全忽略了"invalid json"测试。是否需要对抛出的每个异常分别进行测试?
7条答案
按热度按时间wnrlj8wa1#
即使使用
setExpectedException
,您的测试仍然是常规的PHP代码,并且遵循PHP的常规规则。如果抛出异常,程序流将立即跳出当前上下文,直到到达try
/catch
块。在PHPUnit中,当你使用
setExpectedException
时,它会告诉PHPUnit的核心什么时候应该从即将运行的代码中期待一个异常,因此它会用一个try
/catch
块等待它,如果catch
被用它期待的异常类型调用,它就通过测试。但是,在您的测试方法中,正常的PHP规则仍然适用--当异常发生时,当前代码块就结束了。除非您在测试方法中有自己的
try
/catch
代码块,否则不会执行该方法中的任何其他代码块。因此,为了测试多个异常,您有几个选项:
1.将您自己的
try
/catch
添加到测试方法中,以便在第一个异常之后可以在该方法中进行进一步的测试。1.将测试拆分为单独的方法,以便每个异常都在自己的测试中。
1.这个特定的示例看起来是使用PHPUnit的
dataProvider
机制的一个很好的案例,因为你基本上是用两组数据测试同一个功能。dataProvider
特性允许你定义一个单独的函数,它包含一个数组的输入数据,用于你想要测试的每一组值。然后,这些值一次传递一组到测试方法中。你的代码看起来像这样:bkhjykvo2#
我发现在异常后继续测试的最简单方法是在测试中实现try/finally块,这实质上允许测试继续执行,而不管是否抛出任何异常。
这是我的实现:
1zmg4dgp3#
如果你需要在抛出异常后执行额外的Assert,只需要使用这个模板:
kyks70gy4#
对于任何想做问题标题中的事情的人来说,这是我想出的最干净的事情。
cqoc49vn5#
在@SDC回答的基础上,我提出以下建议
进一步拆分测试
如果Assert与相同的行为不相关,那么单个测试中的多个Assert就会出现问题:无法正确命名测试,甚至可能在测试方法名称中使用
and
。如果发生这种情况,请将测试拆分为单独的测试避免使用SUT的示例属性
当我开始编写测试时,我觉得在
setUp
中安排被测系统(SUT),然后在各个测试中通过相应的示例属性引用SUT时,有机会减少代码重复。这很诱人,但是过了一段时间,当您开始从SUT中提取协作者时,您将需要设置测试副本,在开始时这可能对您仍然有效,但是之后您将开始在不同的测试中 * 以不同的方式 * 设置测试副本,并且所有先前旨在避免的重复都将回到您的身上:您将结束设置两个测试副本,并再次在测试中安排SUT。
当我在代码评审中遇到这种情况时,我喜欢引用
我推荐你阅读一读。
重要的一点是,您希望让编写 * 和 * 维护测试变得容易。(或者任何代码,如果你愿意的话)意味着让代码更容易阅读。如果你读了一些代码,比如说,一个类方法,你想容易地理解它是关于什么的,理想的情况下,这个方法应该做你期望它从类名做的事情。如果你测试不同的行为,通过创建不同的测试方法使其显而易见。
这样做的另一个好处是,如果您使用
您最终会得到一个预期行为的良好列表,请参见
基于您的问题的示例
注意我在这个例子中提供的注解只是为了说明进一步拆分测试的想法,在实际代码中我不会有这些注解。
注意我还建议您查看
hfsqlsce6#
首先,有一个打字错误。替换
第一个月
与
__DIR__
:)
感谢@SDC的评论,我意识到你确实需要为每个异常单独的测试方法(如果你使用PHPUnit的
expectedException
特性)。你代码的第三个Assert没有被执行。如果你需要在一个测试方法中测试多个异常,我建议你在测试方法中编写你自己的try
catch
语句。再次感谢@SDC
cfh9epnr7#
我有这个特质
我是这样称呼它的: