在为该对象编写类之前为对象编写模拟/存根?

Lew*_*ett 8 php phpunit class-design

我正在设计一个有两个依赖项的类.其中一个依赖类已经编写和测试.另一个还没写.

它发生在我身上,因为剩余的依赖关系将被编写以方便将要使用它的类,我应该首先编写后者,然后设计前者的接口,学习它应该做什么.

在我看来,这是制作代码的好方法.毕竟,只要主类在其构造函数中得到一个mock,我就可以编写它并在不知道它的依赖性不存在的情况下测试它,然后我可以创建依赖项,一旦我确定我知道我需要什么.

那么:我该怎么做?创建一个我修改的骨架类.也许是这样的:

class NonExistantSkeleton
{
    public function requiredMethod1()
    {
    }

    public function newlyDiscoveredRequirement()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用PHPUnit模拟它,并设置存根等,以保持我的课程开发愉快?

这是要走的路吗?

这似乎是开发代码的好方法 - 在我看来比开发依赖更有意义,而不确定它将如何被使用.

edo*_*ian 8

简而言之:

是.至少那就是我现在正在做的事情.


更长版本:

如果在您正在构建的课程的测试中,您所在班级的预期合作者不存在,您可以选择以下几种方法:

  • 模拟不存在的类(phpunit可以做)
  • 创建类骨架并模拟它们
  • 只需创建接口并获取那些模拟(phpunit也可以这样做)
  • 根据对象,您可能不需要上述任何一项

如果您对接口进行编程,那么您需要做的就是创建该接口并告诉PHPUnit从中创建存根/模拟

  • +没有考试就没有新班级
  • +在适当时使用接口被认为比仅仅暗示类更好/更好

模拟非现有类时,你会遇到一些我不喜欢的缺点:

  • - 高昂的模拟维护成本
  • - 对这些类的方法进行分析是缓慢而乏味的
  • - 如果你创建了课程,你应该再次修改模拟

所以我建议反对.

中间道路是只创建空的类骨架,其方法和使用那些嘲讽.

我非常喜欢这种方式,在没有接口提示的情况下,因为它很快并且创建稳定的测试代码.

对我来说,使用公共api的准系统课程并不违反TDD.


有些课你不需要模拟.

数据传输对象值对象始终可以使用new生产代码中的任何位置创建,因此您的测试也可以只是真实对象.

它有助于保持您的测试更清洁,因为您不需要模拟/期望很多getter/setter方法等等.


Gor*_*onM 7

如果您遵循开发方法,那么通常的方法如下:

  1. 弄清楚你的课程要做什么,以及面向公众的API应该是什么.
  2. 实现"空"类,除了公共方法符号与空体之外什么都没有(正如您在代码示例中所做的那样).
  3. 制定实施战略.这意味着确定哪些类彼此依赖并按顺序实现它们,这意味着依赖类在它所依赖的类完成之前不会实现,或者至少具有足够的功能来开发.这意味着首先执行没有依赖项的类,然后是仅依赖于已完成的类的类,依此类推.
  4. 写下你的测试.现在可以编写测试,因为你知道你的类的黑盒子是什么样的,他们需要把什么作为输入,以及它们应该作为输出返回什么.
  5. 运行测试.你应该获得0%的成功,但也有100%的代码覆盖率.这是您的基准.
  6. 根据您的实施策略开始实施您的课程.在此过程中不时运行您的单元测试,例如,一旦完成课程,就要确保它符合单元测试中规定的规范.理想情况下,每个测试应显示测试通过的增加,同时保持100%的代码覆盖率.

编辑:正如edorian指出的那样,PHP接口在这里是一个巨大的帮助,因为PHPUnit可以从接口和类生成模拟和存根.它们也是减少耦合和改善可替代性的优秀工具.它们允许您替换实现预期接口的任何类,而不仅仅是期望类的子类.