测试工厂方法

Test factory method

编写测试以覆盖 100% 的代码是我们应该尝试实现的目标。但是我想出了我不知道如何测试方法(工厂方法)的情况:

public function getDocument(){
    $document = new Document();
    $document->settings(new Settings());
    $document->filesystem(new Filesystem('e:'));
    return $document;
}

该方法的目的是创建文档的快捷方式,而不是每次都写3行。

如何测试这个方法?

或者这就是为什么我们有 @codeCoverageIgnoreStart 块的情况?正是出于这个原因,PHPUnit 提供了这种注解。


编辑: 这种方法背后的主要思想是让客户的生活更轻松。仅此而已,没有配置等(但该方法将是执行此操作的好地方)。

//I don't want bother client with Settings() and Filesystem('e:')
$document = new Document(new Settings(), new Filesystem()); //NO
$document = Files.getDocument() //much easier and shorter.

//Changing API to getDocument($var, $var) make no sense, the same thing I could have normally.
$document = new Document(new Settings(),new Filesystem('e:'));

也许我应该考虑一下我是否真的应该提供那个方法,想要使用文档的用户应该知道依赖关系,它不应该被隐藏。

Inject your dependencies (Document, Settings, Filesystem) via the constructor, then use test doubles视情况而定。

也重新考虑一下你的100%覆盖率政策,绝对不清楚这实际上是一件好事。

我找到了答案:此代码不可测试。

Wherever you have new XXX(...) in a method under test, you are doomed.

更多:

将依赖传递给工厂方法,在里面初始化新对象,并适当配置。在测试中,依赖项将是模拟的而不是真实的对象。

方法一

允许创建依赖项的传递工厂:

public function getDocument(SettingsFactory $sf, FilesystemFactory $ff){
    $document = new Document();
    $document->settings($sf->getSettings());
    $document->filesystem($ff->getFilesystem());
    return $document;
}

在测试中,你应该:

  • 创建 Settings 实例或 mock 和一个 SettingsFactory mock 期望一次调用 getSettings 并将 return Settings 实例
  • 创建 Filesystem 实例或 mock 和一个 FilesytemFactory mock 期望一次调用 getFilesystem 并将 return Filesystem 实例
  • 调用DocumentFactory方法,传递工厂。检查 Document 对象是否 returned
  • 检查分配给 Document 的对象是否与您为 return
  • 配置的模拟相同

A 变体getSettingsgetFilesystem 作为 Document 工厂的方法。在那种情况下,您应该创建工厂的部分模拟,并对其设置期望。所以真正的getDocument方法被调用了,但是当getSettingsgetFilesystem方法被调用时,你return控制实例。

方法二

传递实际依赖项:

public function getDocument(Settings $settings, Filesystem $filesystem) {
    $document = new Document();
    $document->settings($settings);
    $document->filesystem($filesystem);
    return $document;
}

在测试中,你应该:

  • 创建Settings实例或模拟
  • 创建Filesystem实例或模拟
  • 调用DocumentFactory方法,传递SettingsFilesystem。检查 Document 对象是否 returned
  • 检查分配给 Document 的对象是否与您传递给工厂方法的实例相同

这个方法有什么作用? Returns 已初始化 Document 对象。因此,您只需验证返回值是一个 Document 实例,并且它已设置 SettingsFilesystem 对象。如果你有这些吸气剂就很容易,否则你必须访问各自的属性。

该测试听起来可能非常基础,但它确实测试了它需要的东西。当您以注入设置和文件系统的方式重构代码时,测试仍会告诉您文档是否设置了这些属性。

之所以称为 unit testing,是因为您正在测试 unit,而不是对象或方法。如果你的单位有多个类,随它去吧。不需要注入所有东西,也不需要模拟所有东西——这些东西可以简化测试,但在某些情况下最好不要模拟它们