依赖注入和单元测试的新手。
原因部分:
有一些dll:
WindowsService仅引用Common.dll以便更轻松地进行测试,版本控制和部署。
问题是ProductA和B.dll中的任何依赖项都无法从WindowsService发送到Common dll,因为它需要WindowsService中的程序集引用到ProductA和B(不想要)
因此,在Common.dll中调用代码时,单元测试无法隔离依赖项。
因此,为了隔离依赖项,代码有一个重载的构造函数,它只公开依赖项以进行测试。
这可以吗?
见下面的例子:
单元测试将模拟依赖项并调用重载的构造函数,但实际代码调用默认构造函数
public class ClassUnderTest
{
private ISomeDependency a;
private IOtherDependency b;
// constructor called by code
public ClassUnderTest()
{
this.a = new SomeDependency();
this.b = new OtherDependency();
}
public ClassUnderTest(ISomeDependency a, IOtherDependency b)
{
this.a = a;
this.b = b;
}
}
答案 0 :(得分:2)
我很惊讶没有人提到你可以使用构造函数链接。
public class ClassUnderTest
{
readonly ISomeDependency a;
readonly IOtherDependency b;
public ClassUnderTest() : this(new SomeDependency(), new OtherDependency())
{
}
public ClassUnderTest(ISomeDependency a, IOtherDependency b)
{
this.a = a;
this.b = b;
}
}
虽然我从根本上同意所有说过IOC容器是最佳方法的人。
答案 1 :(得分:1)
我建议你让IOC容器注入依赖项,而不是直接实例化你的具体类。如果这样做,您可以在两种情况下使用第二个构造函数(构造函数注入)。另一种方法是在类上定义公共属性并进行属性注入。
但是,如果您没有使用IOC容器,而是执行“手动依赖注入”,我认为当前模式没有任何问题。可以在代码中创建“钩子”以便于测试。
答案 2 :(得分:1)
使用依赖注入,最终必须注入依赖项。我更喜欢使用依赖注入容器来实现此目的。这是捕获:构成组件的对象需要具有对所有实际对象的程序集引用。
有几种方法可以做到这一点:
真正的问题是你的构造函数。要正确测试,您需要让测试代码和生产代码使用相同的构造函数。这就是存在依赖注入容器的原因:处理为每个接口引用创建的对象的详细信息。
答案 3 :(得分:0)
但实际代码调用默认构造函数
在这种情况下,您的测试告诉您没有任何帮助您找出“真正的”代码在生产中爆炸的原因没有用,因为您实际上没有测试默认构造函数。
虽然我同意其他答案并敦促您使用IoC容器,但如果确实希望保留您当前拥有的模式,那么至少会暴露在默认情况下创建的依赖项{ {1}}作为公共属性,以便您可以测试它们:
ctor
也是依赖引用。
如果您将public class ClassUnderTest
{
readonly ISomeDependency a;
readonly IOtherDependency b;
public ISomeDependency A{Get{return a;}}
public ISomeDependency B{Get{return b;}}
// constructor called by code
public ClassUnderTest()
{
this.a = new SomeDependency();
this.b = new OtherDependency();
}
}
[TestMethod]
public void DefaultCTOR_CreatesDependencies()
{
var sut = new ClassUnderTest();
Assert.IsNotNull(sut.A,"sut didn't create SomeDependency A");
Assert.IsNotNull(sut.B,"sut didn't create OtherDependency B");
}
和ISomeDependency
移动到他们自己的程序集中(不实现),那么您将能够从IOtherDependency
和ProductA
引用此dll ProductB
个程序集以及Common
ISomeDependency
的请求解析为具体对象,并将这些对象提供给Common
,{{ 1}}和ProductA
纯粹是通过接口,他们将不会更聪明:)