如何在单元测试中正确使用IoC?

时间:2014-12-12 09:41:41

标签: c# wpf unit-testing c#-4.0 mef

我们有一个WPF应用程序。 许多ViewModel使用必须模拟的相同依赖项。 有时,ViewModel的构造函数具有太多依赖性(过度注入),只有意图暴露 - 允许单元测试。 例如:

[ImportingConstructor]
public PasswordInputViewModel(
    IPaymentSystemProvider provider,
    IAppContext appCtx,
    IEventAggregator eventAggregator,
    IPromptCreator promptCreator) {
}

关键是三个依赖项是来自基础结构的依赖项。将它们公开用于显式注入以及允许单元测试的唯一意图比ViewModel的依赖性的有用信息增加更多噪声。特别是,因为几乎所有的VM都有这些依赖关系。

因此,我们将这些依赖项移到了BaseViewModel类:

public class ScreenExtended : Screen {
    [Import]
    public IEventAggregator eventAggregator { get; private set; }

    [Import]
    public IPromptCreator Prompt { get; private set; }

    [Import]
    public IAppContext CurrentApp { get; private set; }
}

现在,我们需要从避免构造函数注入的单元测试中以某种方式模拟它们。 所以,我们可以引导IoC。

现在的问题是: 如何在这里正确使用IoC?为每个类或每个测试引导IoC,或者使其静态并仅初始化一次?如果我们使它静止,我们需要以某种方式重新组合IoC。你会推荐什么?

2 个答案:

答案 0 :(得分:1)

我想说这取决于注入的项是具体实现还是模拟对象。如果您正在使用具体实现,那么如果您在类级别初始化,则可能会在测试之间出现状态问题。

我通常会重新初始化每个测试的每个依赖项,甚至是一个具体的类(在模拟存储库之上模拟服务层)。在测试CRUD类型功能时,尽管需要更长的时间,但确实能够将每个测试重置为零。而是可以在隔离或列表中正确可靠地运行测试。

答案 1 :(得分:0)

  

有时候,ViewModel的构造函数有太多依赖(过度注入)暴露的唯一意图 - 允许单元测试。

如果依赖关系太多,则更有可能违反单一责任原则。

在提供的ViewModel的上下文中,有4个依赖项是违规吗?这个问题没有正确的答案(即主观问题)。应该存在依赖性平衡:不是太少,也不是太多。

  

关键是三个依赖项是来自基础结构的依赖项。将它们公开用于显式注入以及允许单元测试的唯一意图比ViewModel的依赖性的有用信息增加更多噪声。特别是,因为几乎所有的VM都有这些依赖关系。

强制执行单一责任原则的建议非常抽象,因为需要更多ViewModel - 类来查看(它们对依赖项的使用):引入一个抽象层来封装高级操作的实现。它可能听起来太大了#34;但它可能只是一个Facade,它隐藏了高级操作的实现细节(使用基础设施服务等)。

  

现在,我们需要从避免构造函数注入的单元测试中以某种方式模拟它们。所以,我们可以引导IoC。

除非绝对需要,否则请考虑使用构造函数注入和实现单元测试,而不使用具体的DI容器API。单元测试不应取决于具体DI容器的API。