PHPUnit:单个测试中出现多个断言,仅看到第一个失败
我在 PHPUnit 中看到的下一个奇怪之处是:
class DummyTest extends PHPUnit_Framework_TestCase {
public function testDummy() {
$this->assertTrue(false, 'assert1');
$this->assertTrue(false, 'assert2');
}
public function testDummy2() {
$this->assertTrue(false, 'assert3');
}
}
一旦第一个断言在测试中失败,测试的其余部分就会被忽略。
所以(通过简单调用 phpunit DummyTest.php):
上面的代码将显示 2 个测试, 2 断言,2 失败。什么?
如果我通过了所有测试,那么 我会没事的(2个测试,3个断言)。 很好。
如果我只通过所有测试 除了断言2之外,我得到了2个测试,3个 断言,1 次失败。很好。
我不明白,但 PHPUnit 已经存在很多年了,肯定是我吧?
不仅计数不是我所期望的,而且仅显示上面代码中第一个失败断言的错误消息。
(顺便说一句,我正在分析 PHPUnit 为 CI 生成的 xml 格式,而不是测试真实代码,因此在一次测试中采用了多个断言的做法。)
The next weirdness I'm seeing with PHPUnit:
class DummyTest extends PHPUnit_Framework_TestCase {
public function testDummy() {
$this->assertTrue(false, 'assert1');
$this->assertTrue(false, 'assert2');
}
public function testDummy2() {
$this->assertTrue(false, 'assert3');
}
}
As soon as the first assertion fails in a test, the rest of the test is ignored.
So (with a simple call of phpunit DummyTest.php):
The above code will display 2 tests,
2 assertions, 2 failures. What?If I make all the tests pass, then
I'll get OK (2 tests, 3 assertions).
Good.If I only make all the tests pass
except for assert2, I get 2 tests, 3
assertions, 1 failure. Good.
I don't get it, but PHPUnit's been around for ages, surely it has to be me?
Not only are the counts not what I'd expect, only the error message for the first failed assert in the code above is displayed.
(BTW, I'm analyzing the xml format generated by PHPUnit for CI rather than testing real code, hence the practice of multiple assertions in the one test.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先:这是预期的行为。
一旦断言失败,每个测试方法都会停止执行。
举个例子,相反的情况会非常烦人*:
如果 phpunit 在第一个断言后没有停止,你会得到一个 E_FATAL (调用非成员函数),并且整个 PHP 进程将会终止。
因此,要制定良好的断言和小型测试,这种方式更实用。
另一个例子:
当“断言一个数组的大小为 X,然后断言它包含 a,b 和 c”时,你不关心它不包含这些值的事实如果大小为 0。
如果测试失败,您通常只需要消息“为什么失败”,然后在修复它时,您将自动确保其他断言也通过。
另外,还有人认为你应该只拥有
每个测试用例一个断言
虽然我不练习(而且我不确定我是否喜欢它),但我想记下它;)First off: That is expected behavior.
Every test method will stop executing once an assertion fails.
For an example where the opposite will be very annoying*:
if phpunit wouldn't stop after the first assertion you'd get an E_FATAL (call to a non member function) and the whole PHP process would die.
So to formulate nice assertions and small tests it's more practical that way.
For another example:
When "asserting that an array has a size of X, then asserting that it contains a,b and c" you don't care about the fact that it doesn't contain those values if the size is 0.
If a test fails you usually just need the message "why it failed" and then, while fixing it, you'll automatically make sure the other assertions also pass.
On an additional note there are also people arguing that you should only have
One Asssertion per Test case
while I don't practice (and I'm not sure if i like it) I wanted to note it ;)欢迎来到单元测试。每个测试功能应该测试一个元素或流程(流程是用户可能采取的一系列操作)。 (这是一个单元,以及为什么它被称为“单元测试”。)在测试函数中应该有多个断言的唯一情况是测试的一部分依赖于前一部分的成功。
我用它来测试 Selenium 网页。因此,我可能想断言每次导航到新页面时我都处于正确的位置。例如,如果我进入网页,然后登录,然后更改我的个人资料,我会断言登录时我到达了正确的位置,因为如果登录失败,测试将不再有意义。当实际只遇到一个问题时,这可以防止我收到其他错误消息。
另一方面,如果我有两个单独的进程要测试,我不会测试一个进程,然后继续在同一函数中测试另一个进程,因为第一个进程中的错误会掩盖第二个进程中的任何问题。相反,我会为每个进程编写一个测试函数。 并且,如果一个进程依赖于另一个进程的成功,例如,将某些内容发布到页面,然后删除该帖子,我将使用 @depends 注释来防止在第一个测试失败时运行第二个测试。)
( ,如果您的第一个断言失败并不会使第二个断言无法测试,那么它们应该位于单独的函数中。 (是的,这可能会导致冗余代码。在单元测试时,忘记所有关于消除冗余代码的知识。或者创建非测试函数并从测试函数中调用它们。这会使单元测试更难阅读,因此,当测试主题发生变化时,更新会更困难。)
我意识到这个问题已经有两年了,但是唯一的答案并不清楚为什么。我希望这可以帮助其他人更好地理解单元测试。
Welcome to unit testing. Each test function should test one element or process (process being a series of actions that a user might take). (This is a unit, and why it is called "unit testing.") The only time you should have multiple assertions in a test function is if part of the test is dependent on the previous part being successful.
I use this for Selenium testing web pages. So, I might want to assert that I am in the right place every time I navigate to a new page. For instance, if I go to a web page, then login, then change my profile, I would assert that I got to the right place when I logged in, because the test would no longer make sense if my login failed. This prevents me from getting additional error messages, when only one problem was actually encountered.
On the other side, if I have two separate processes to test, I would not test one, then continue on to test the other in the same function, because an error in the first process would mask any problems in the second. Instead, I would write one test function for each process. (And, if one process depended on the success of the other, for instance, post something to a page, then remove the post, I would use the @depends annotation to prevent the second test from running if the first fails.)
In short, if your first assert failing does not make the second one impossible to test, then they should be in separate functions. (Yes, this might result in redundant code. When unit testing, forget all that you have learned about eliminating redundant code. That, or make non-test functions and call them from the test functions. This can make unit tests harder to read, and thus harder to update when changes are made to the subject of the tests though.)
I realize that this question is 2 years old, however the only answer was not very clear about why. I hope that this helps others understand unit testing better.