Php 试验工厂法
编写测试以覆盖100%的代码是我们应该尝试实现的目标。但我想到了我不知道如何测试方法(工厂方法)的情况: 该方法的目的是创建文档的快捷方式,无需每次写3行 如何测试这种方法 或者这就是为什么我们有@codecoverageignostart块的原因?正是出于这个原因,PHPUnit不提供这种注释Php 试验工厂法,php,unit-testing,phpunit,Php,Unit Testing,Phpunit,编写测试以覆盖100%的代码是我们应该尝试实现的目标。但我想到了我不知道如何测试方法(工厂方法)的情况: 该方法的目的是创建文档的快捷方式,无需每次写3行 如何测试这种方法 或者这就是为什么我们有@codecoverageignostart块的原因?正是出于这个原因,PHPUnit不提供这种注释 编辑: 这种方法背后的主要思想是让客户的生活更轻松。没有更多,没有配置等(但该方法将是一个很好的地方) 也许我应该考虑一下,如果我真的应该提供那个方法,想要使用文档的用户应该知道依赖关系,它不应该被隐
编辑: 这种方法背后的主要思想是让客户的生活更轻松。没有更多,没有配置等(但该方法将是一个很好的地方) 也许我应该考虑一下,如果我真的应该提供那个方法,想要使用文档的用户应该知道依赖关系,它不应该被隐藏。(
文档
,设置
,文件系统
)通过构造函数,然后根据需要使用
再重新考虑一下你的100%覆盖率政策,这绝对不是一件好事。我发现答案有点像:这段代码是不可测试的 无论您在测试的方法中有新的XXX(…),您都注定要失败 更多:
将依赖项传递给工厂方法,初始化内部的新对象,并正确配置它。在测试中,依赖项将是模拟而不是真实对象 方法1 传递允许创建依赖项的工厂:
public function getDocument(SettingsFactory $sf, FilesystemFactory $ff){
$document = new Document();
$document->settings($sf->getSettings());
$document->filesystem($ff->getFilesystem());
return $document;
}
public function getDocument(Settings $settings, Filesystem $filesystem) {
$document = new Document();
$document->settings($settings);
$document->filesystem($filesystem);
return $document;
}
在测试中,您应该:
- 创建
instance或mock和一个Settings
mock,该mock需要调用SettingsFactory
,并返回getSettings
实例Settings
- 创建
实例或mock和一个Filesystem
mock,该mock需要调用filesystemfactory
,并将返回getFilesystem
实例Filesystem
- 调用
方法,传递工厂。检查是否返回了DocumentFactory
对象文档
- 检查分配给
的对象是否与配置模拟返回的对象相同文档
getSettings
和getFilesystem
作为文档
工厂的方法。在这种情况下,您应该创建工厂的部分模拟,并对其设置期望值。因此调用了真正的getDocument
方法,但是当调用getSettings
和getFilesystem
方法时,返回受控实例
方法2
传递实际依赖项:
public function getDocument(SettingsFactory $sf, FilesystemFactory $ff){
$document = new Document();
$document->settings($sf->getSettings());
$document->filesystem($ff->getFilesystem());
return $document;
}
public function getDocument(Settings $settings, Filesystem $filesystem) {
$document = new Document();
$document->settings($settings);
$document->filesystem($filesystem);
return $document;
}
在测试中,您应该:
- 创建
实例或模拟设置
- 创建
实例或模拟文件系统
- 调用
方法,传递DocumentFactory
和设置
。检查是否返回了文件系统
对象文档
- 检查分配给
文档
的对象是否与传递给factory方法的实例相同
文档
对象。因此,您只需验证返回的值是否为文档
实例,以及是否设置了设置
和文件系统
对象。如果您有这些的getter,那么很容易,否则您必须访问相应的属性
这个测试听起来很基本,但它确实测试了它需要测试的东西。当您以注入设置和文件系统的方式重构代码时,测试仍然会告诉您文档是否设置了这些属性
它被称为
单元测试
,因为您测试的是单元
,而不是对象或方法。如果你的单位有多个班级,就让它去吧。不需要所有的东西都被注入,也不需要所有的东西都被模仿——这些东西易于测试,但在某些情况下,最好不要模仿它们有什么问题?对于这个方法,需要测试文档是否有明确的设置和文件系统。但在单元测试中,我们不应该依赖依赖依赖项,所以即使设置或文件系统类尚未定义,测试也应该通过。@tne说的是正确的答案。阅读关于依赖性注射。好的,我明白你们的意思,这将允许我测试方法。但我每次创建文档时都需要新的实例。你的想法很好,我理解。感谢您写下答案,一般来说,您的解决方案类似于那些表单注释I链接:(请再次执行此操作:)。我编辑了我的问题,请看。依赖注入可以通过使用一些库来管理:@SonnyD如果你认为答案解决了你的问题,那么你应该礼貌地接受最好的答案,同时也可以帮助这个问题的未来观众知道正确的解决方案是什么。我跳过测试这个方法。但我可能会使用断言。我没有用于文件系统设置的getter,因为它们不应该从文档中访问。为了检查它,我将使用ReflectionClass。至于第二部分,我不知道……在我对单元测试的思考中(可能是错误的),我们不应该使用依赖项的原始实现(这就是我想要摆脱的),所有这些都应该被模仿(存根,伪造)。我们正在测试“单元”,但必须在单独的环境中进行测试,我们可以轻松地进行配置。测试这个特定的“单元”应该通过测试,而不需要测试“单元”之外的任何东西。@SonnyD我建议你阅读Steve Freeman的书(或者更好,他写的书《由测试引导的面向对象软件的成长》),这是(真正的)很好的建议。我认为是否模拟和是否反转依赖关系(例如注入)的问题是完全不同的。我建议OP对API进行评估,以决定是否将其置于适配器之后(如果可以最小化API,则建议使用模拟库,否则只要接口稳定且最小,则使用模拟库可能更合适)。我同意你的看法