c# - 避免在可测试方法内创建存储库的架构

标签 c# unit-testing architecture

正在开发 MVVM 应用程序。每个 ViewModel 类都有一个接受 Repository 类的构造函数,以便可以模拟它以进行单元测试。

该应用程序设计为同时跨多个窗口操作。因此它包含许多“View”或“Open”样式的方法,这些方法创建新的 ViewModel 并将它们放入新窗口中。因为这些是通过 UI 触发的,所以它们通常位于现有的 ViewModel 中。例如:

public void ViewQuote(Quote quote)
{
    if (quote.CreatedOn == null)
    {
        quote.CreatedOn = DateTime.Now;
    }

    NavigationHelper.NewWindow(this, new QuoteViewModel(quote, new Repository()));
}

现在,该流程控制语句看起来值得测试,以确保为空 CreatedOn 日期传递的引号分配一个值。然而,我对此的测试失败了,因为尽管父 ViewModel 有一个模拟的存储库,但 NewWindow 方法会启动一个新的 ViewModel,其中包含一个真实的存储库。当在该类的构造函数中使用它时,这会引发错误。

有两个明显的选择。

一种是将日期分配提取到独立函数中进行测试。这会起作用,但对于它自己的功能来说似乎太简单了。另外,如果我在整个应用程序中执行此操作,则可能会产生太多碎片以方便阅读。

另一种方法是以某种方式更改 ViewModel 的构造函数代码,使其不直接使用存储库。这可能是一个选项,但它不太可能适用于所有可能的情况。

或者是否有第三种方法可以更好地设计它,以便我可以将模拟的存储库传递到新 ViewModel 的构造函数中?

最佳答案

新建服务(或类似服务的对象,例如存储库)是一种设计味道。您遇到的问题就是结果。

换句话说,你缺乏一个清晰明确的Composition Root .

解决方案:使用正确的依赖注入(inject)

对此唯一干净的解决方案是通过构造函数注入(inject)服务。存储库的生命周期通常比应用程序本身短,因此在这种情况下,您将注入(inject)一个能够创建存储库的工厂。

请注意,清晰的依赖树是很好的设计,但使用 DI 框架,如 Autofac只是实现这种设计的一种技术方案。您可以完全解决您的问题并创建一个干净的组合根,而无需使用 DI 框架。

因此,尽管这可能需要大量工作,但您应该重新设计应用程序以具有清晰的组合根。否则,你会一次又一次地遇到小问题,尤其是在测试领域。

关于c# - 避免在可测试方法内创建存储库的架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34178231/

相关文章:

CSS 最佳实践问题

c# - 身份 2.0 用户身份在 MVC 5 Controller 初始化程序中为空

c# - 将 Func<T, string>[] 转换成 Func<T, string[]>?

c# - "Keyword not supported"MySQL C#

android - 模拟位置不适用于 Android Pie 及更高版本

c# - 使用 out 参数在 NSubstitute 模拟方法中返回不同的值

c# - 如何区分意外(骨头)异常与预期(外来)异常?

c# - 内联隐式声明的输出变量编译但不获得 Visual Studio 支持

visual-studio - VS2010 中的单元测试 3.5 项目产生 CS1685 警告

c - C 中整数或任何其他数据类型的大小是否取决于底层架构?