何时使用存根/模拟,何时在单元测试中使用真实对象?

2022-01-25 00:00:00 mocking unit-testing php phpunit

我最近试图提高我的单元测试技能并阅读了很多关于单元测试的文献,我还试图实现我在我目前正在使用 phpunit 开发的一个 php 项目中学到的东西.但在我看来,我仍然有一个非常基本的问题,如何对与其他类的对象甚至与同一类的其他方法交互的方法进行单元测试.

I recently tried to improve my unit testing skills and read quite some literature about unit testing and I am also trying to realize what I learned in a php-project I am currently developing with phpunit. But I still have a in my opinion very fundamental question how to unit test methods which interact with objects of other classes or even with other methods of the same class.

是否有一些经验法则或一些帮助我可以决定我应该存根/模拟哪些依赖项以及我应该简单地使用普通对象的依赖项?为了澄清我的问题,这是一个示例代码,具有不同的场景:

Is there some rule of thumb or some help how I can decide what dependencies I should stub/mock and for what dependencies I should simply use a normal object? To clarify my question, here is an example code, with different scenarios:

interface DependencyInterface {
    public method dependentMethod() { ... }
}
class Dependency implements DependencyInterface {...}

class ClassUnderTest {
    private $dependency
    public __construct(DependencyInterface $dependency) {
        $this->dependency = dependency;
    }
    public function methodUnderTest() {
        ...
        $result1 = $this->dependency->dependentMethod();
        ...
        $result2 = $this->otherMethod();
        ...
        $result3 = $this->usedInMultiplePublicMethods();
    }

    public function otherMethod() {...}
    private function usedInMultiplePublicMethods() {...}
}

所以我现在的问题是针对测试方法 methodUnderTest 的功能的单元测试,我应该:

So my questions are now for a unit test which tests the functionality of the method methodUnderTest, should I:

  1. 存根 DependencyInterface 接口并将其注入到构造函数中,还是我应该简单地使用实现 Dependency 的一个实例?
  2. 部分存根 ClassUnderTest 类本身,以便为 otherMethod 提供固定结果,因为这个可能非常复杂的方法已经拥有自己的完整单元测试?
  3. 我决定不对私有方法进行单元测试,因为它们不是类接口的一部分(我知道这是一个有争议的话题,不在我的问题范围内).我现在是否必须为每个使用私有方法 usedInMultiplePublicMethods 的公共方法涵盖私有方法中可能发生的所有可能影响?还是应该只在使用它的一种公共方法中测试所有可能的影响,并在所有其他公共方法的测试中存根私有方法?

我不太确定何时使用存根/模拟,何时不使用.

I am quite not sure about when to use stubbing/mocking and when not.

推荐答案

mock的原因是要能写出单元测试,即测试是:快速、隔离、可重复、自我验证、Thorough and Timely (FIRST)

The why of mocking is to be able to write unit test that means a test which is: fast, isolated, repeatable, self validating and Thorough and Timely (F.I.R.S.T)

为了能够单独测试单元/模块,您可能需要模拟/存根任何外部模块(数据库访问、api 调用、日志记录系统...).

To be able to test a unit/module in isolation you may need to mock/stub any external module (database access, api call, logging system...).

相关文章