Sib*_*Guy 3 .net c# dependency-injection
首先让我介绍没有依赖注入的实现(这将打破依赖反转原则):
public class MyValidator
{
private readonly IChecksumGenerator _checksumGenerator;
public MyValidator()
{
_checksumGenerator = new MyChecksumGenerator();
}
...
}
Run Code Online (Sandbox Code Playgroud)
为了使此代码可测试,请注入IChecksumGenerator:
public class MyValidator
{
private readonly IChecksumGenerator _checksumGenerator;
public MyValidator(IChecksumGenerator checksumGenerator)
{
_checksumGenerator = checksumGenerator;
}
...
}
Run Code Online (Sandbox Code Playgroud)
现在,如果需要,我们可以轻松地测试MyValidator和stub checksumGenerator。但是MyValidator实现在算法上与特定的IChecksumGenerator实现耦合(它不能与任何其他实现一起使用)。因此出现一些问题:
我想到的最好的解决方案是:
public class MyValidator
{
private readonly IChecksumGenerator _checksumGenerator;
public MyValidator()
{
_checksumGenerator = new MyChecksumGenerator;
}
internal MyValidator(IChecksumValidator checksumValidator)
{
_checksumValidator = checksumValidator;
}
...
}
Run Code Online (Sandbox Code Playgroud)
在这里,我介绍了用于测试目的的特殊构造函数(因此我可以在测试中对IChecksumValidator进行存根),但是公共构造函数将创建与之耦合的实现(因此封装不会中断)。创建一些用于测试目的的代码有点难看,但是看起来在这种情况下是有意义的。
您将如何解决这个问题?
重构为构造函数注入是一个很好的主意,但是我发现问题中提出的约束很奇怪。我建议您重新考虑设计。
如果MyValidator仅与IChecksumGenerator的一种特定实现一起使用,则将违反Liskov替代原则(LSP)。从本质上讲,这也意味着您将无法插入测试Double,因为存根/模拟/伪造/无论什么都不是“正确的” IChecksumGenerator的实例。
从某种意义上讲,您可以说该API 取决于其要求,因为它声称它可以处理任何IChecksumGenerator,而实际上它仅适用于一种特定类型-我们将其称为OneAndOnlyChecksumGenerator。虽然我建议重新设计应用程序以遵守LSP,但是您也可以更改构造函数签名以诚实地满足要求:
public class MyValidator
{
private readonly OneAndOnlyChecksumGenerator checksumGenerator;
public MyValidator(OneAndOnlyChecksumGenerator checksumGenerator)
{
this.checksumGenerator = checksumGenerator;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
通过使战略成员成为虚拟人员,您仍然可以将OneAndOnlyChecksumGenerator转换为Test Double,从而可以创建特定于测试的子类。
| 归档时间: |
|
| 查看次数: |
424 次 |
| 最近记录: |