PHPUnit:在单个测试中有多个断言,仅看到第一次失败

2022-08-30 21:40:45

我在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个断言)。好。

  • 如果我只让除 assert2 之外的所有测试都通过,我得到 2 个测试,3 个断言,1 个失败。好。

我不明白,但是PHPUnit已经存在了很长时间,它肯定是我吗?

不仅计数不是我所期望的,而且只显示上述代码中第一个失败断言的错误消息。

(顺便说一句,我正在分析PHPUnit为CI生成的xml格式,而不是测试真实代码,因此在一次测试中练习多个断言。


答案 1

首先:这是预期的行为。

一旦断言失败,每个测试方法都将停止执行

举个例子,相反的情况会非常烦人*

class DummyTest extends PHPUnit_Framework_TestCase {
    public function testDummy() {
        $foo = get_me_my_foo();
        $this->assertInstanceOf("MyObject", $foo);
        $this->assertTrue($foo->doStuff());
    } 
}

如果phpunit在第一个断言后不停止,你会得到一个E_FATAL(调用非成员函数),整个PHP进程就会死。

因此,要制定漂亮的断言和小测试,这样更实用。

再举一个例子:

当“断言数组的大小为X,然后断言它包含a,b和c”时,如果大小为0,则您并不关心它不包含这些值的事实。

如果测试失败,您通常只需要消息“为什么失败”,然后在修复它时,您将自动确保其他断言也通过。


另外,还有人认为,在我不练习的时候,每个测试用例应该只有一个Asssertion(我不确定我是否喜欢它),我想把它记;)


答案 2

欢迎来到单元测试。每个测试函数应测试一个元素或进程(进程是用户可能执行的一系列操作)。(这是一个单元,以及为什么它被称为“单元测试”。只有在测试函数中应具有多个断言时,测试的一部分是否依赖于前一部分是否成功。

我用它来测试硒网页。因此,我可能想断言,每次导航到新页面时,我都处于正确的位置。例如,如果我转到一个网页,然后登录,然后更改我的个人资料,我会断言我在登录时到达了正确的位置,因为如果我的登录失败,测试将不再有意义。这可以防止我在实际遇到一个问题时收到其他错误消息。

另一方面,如果我有两个单独的进程要测试,我不会测试一个,然后继续在同一函数中测试另一个进程,因为第一个进程中的错误会掩盖第二个进程中的任何问题。相反,我会为每个进程编写一个测试函数。(而且,如果一个进程依赖于另一个进程的成功,例如,将某些内容发布到页面,然后删除该帖子,我将使用@depends注释来防止在第一个测试失败时运行第二个测试。

简而言之,如果第一个断言失败不会使第二个断言无法测试,则它们应该在单独的函数中。(是的,这可能会导致代码冗余。在单元测试时,忘记你所学到的关于消除冗余代码的所有知识。或者创建非测试函数并从测试函数调用它们。这可能会使单元测试更难阅读,因此在对测试主题进行更改时更难更新。

我意识到这个问题已经2年了,但是唯一的答案不是很清楚为什么。我希望这有助于其他人更好地理解单元测试。


推荐