关于php:如何使用PHPUnit来测试调用同一类的其他方法但不返回任何值的方法

How to use PHPUnit to test a method that calls other methods of the same class, but returns no value

如何为调用同一类的其他方法但不返回值的方法编写单元测试? (让我们说PHPUnit。)

例如,假设我有以下类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyClass {

    public function doEverything() {

        $this->doA;
        $this->doB;
        $this->doC;

    }

    public function doA() {
        // do something, return nothing
    }

    public function doB() {
        // do something, return nothing
    }

    public function doC() {
        // do something, return nothing
    }

}

你会如何测试doEverything()

编辑:

我问这个是因为从我看过的内容看来,几乎所有的方法都应该有自己的专用单元测试。 当然,你也有功能和集成测试,但那些目标特定的例程,可以这么说(不是必须在每个方法级别)。

但是,如果几乎所有方法都需要自己的单元测试,那么我认为对所有上述方法进行单元测试将是"最佳实践"。是/否?


好的!我已经明白了!正如可以预料的那样,在这种情况下我需要模拟 - 而模拟兄弟方法被称为部分模拟。在Juan Treminio的这篇文章中有关于PHPUnit模拟的一些非常好的信息。

所以要在上面的类中测试doEverything(),我需要做这样的事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public function testDoEverything()
{

    // Any methods not specified in setMethods will execute perfectly normally,
    // and any methods that ARE specified return null (or whatever you specify)
    $mock = $this->getMockBuilder('\MyClass')
        ->setMethods(array('doA', 'doB', 'doC'))
        ->getMock();

    // doA() should be called once
    $mock->expects($this->once())
         ->method('doA');

    // doB() should be called once
    $mock->expects($this->once())
         ->method('doB');

    // doC() should be called once
    $mock->expects($this->once())
         ->method('doC');

    // Call doEverything and see if it calls the functions like our
    // above written expectations specify
    $mock->doEverything();
}

而已!满容易!

奖励:如果你使用Laravel和Codeception ......

我正在使用Laravel框架以及Codeception,这使得弄清楚它有点棘手。如果你使用Laravel和Codeception,你需要做更多的工作,因为Laravel自动加载不会默认连接到PHPUnit测试。您基本上需要更新unit.suite.yml以包含Laravel4,如下所示:

1
2
3
4
5
6
# Codeception Test Suite Configuration

# suite for unit (internal) tests.
class_name: UnitTester
modules:
    enabled: [Asserts, UnitHelper, Laravel4]

更新文件后,请不要忘记调用php codecept.phar build来更新配置。


虽然您的模拟测试确实达到了目标,但我认为您对代码的信心降低了。将原始的简单方法与测试它的复杂方法进行比较。被测方法失败的唯一方法是忘记添加其中一个方法调用或输入错误的名称。但是你现在可能会用所有额外的代码做到这一点,而且它没有任何测试!

Rule: If your test code is more complicated than the code under test, it needs its own tests.

鉴于上述情况,您最好找到另一种方法来测试原始代码。对于所写的方法 - 没有参数的三个方法调用 - 通过眼球检查就足够了。但我怀疑该方法确实在某处有一些副作用,否则你可以删除它。

单元测试是关于将类作为一个单元进行测试,而不是单独测试每个方法。单独测试每种方法都可以很好地表明您在代码之后编写测试。使用测试驱动开发并首先编写测试将帮助您设计更易于测试的更好的类。