我们有一个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。你会推荐什么?
答案 0 :(得分:1)
我想说这取决于注入的项是具体实现还是模拟对象。如果您正在使用具体实现,那么如果您在类级别初始化,则可能会在测试之间出现状态问题。
我通常会重新初始化每个测试的每个依赖项,甚至是一个具体的类(在模拟存储库之上模拟服务层)。在测试CRUD类型功能时,尽管需要更长的时间,但确实能够将每个测试重置为零。而是可以在隔离或列表中正确可靠地运行测试。
答案 1 :(得分:0)
有时候,
ViewModel
的构造函数有太多依赖(过度注入)暴露的唯一意图 - 允许单元测试。
如果依赖关系太多,则更有可能违反单一责任原则。
在提供的ViewModel
的上下文中,有4个依赖项是违规吗?这个问题没有正确的答案(即主观问题)。应该存在依赖性平衡:不是太少,也不是太多。
关键是三个依赖项是来自基础结构的依赖项。将它们公开用于显式注入以及允许单元测试的唯一意图比ViewModel的依赖性的有用信息增加更多噪声。特别是,因为几乎所有的VM都有这些依赖关系。
强制执行单一责任原则的建议非常抽象,因为需要更多ViewModel
- 类来查看(它们对依赖项的使用):引入一个抽象层来封装高级操作的实现。它可能听起来太大了#34;但它可能只是一个Facade,它隐藏了高级操作的实现细节(使用基础设施服务等)。
现在,我们需要从避免构造函数注入的单元测试中以某种方式模拟它们。所以,我们可以引导IoC。
除非绝对需要,否则请考虑使用构造函数注入和实现单元测试,而不使用具体的DI容器API。单元测试不应取决于具体DI容器的API。