在 Composite WPF (Prism) 中,我应该如何对我的控制器进行单元测试?

2024-05-27

我正在使用一个模块构建一个基本的复合 WPF Shell。我想对我的模块进行单元测试。显然,Composite WPF 以一种易于单元测试的方式模块化我的代码。

下面是我想要进行单元测试的代码。它驻留在我的模块的控制器中。请注意标准复合 WPF 实体(如区域、演示者、模型等)的使用。

    public void ShowPlantTreeView()
    {
        IRegion navRegion = this.regionManager.Regions[RegionNames.NavigationRegion];
        IPlantTreeView view = navRegion.GetView(typeof(IPlantTreeView).Name) as IPlantTreeView;
        if (view == null)
        {
            view = this.container.Resolve<IPlantTreePresentationModel>().View;
            navRegion.Add(view, typeof(IPlantTreeView).Name);
        }

        view.Model.LastRefreshDateTime = DateTime.Now;
        navRegion.Activate(view);
    }

这只是我想要进行单元测试的七行代码。还不错。问题在于它依赖于许多外部组件 - RegionManager、View、Presentation Model 等。

为了独立测试这一点,我模拟了外部组件。这些使用 Unity 容器通过构造函数注入传递到我的控制器中。为了配置它并进行简单的测试,我的单元测试如下所示......

(看看这个方法的长度!肯定有更好的测试方法?复合 WPF 真的让我的生活更轻松吗?而且我每次测试都必须这样做?!)

    [TestMethod]
    public void TestShowPlantTree()
    {
        //Setup Mocks.
        var plantTreePresentationModel = new Mock<IPlantTreePresentationModel>();
        var plantTreeViewMock = new Mock<IPlantTreeView>();
        var navRegionMock = new Mock<IRegion>();
        var plantTreeModuleMock = new Mock<IPlantTreeModule>();
        var regionManagerMock = new Mock<IRegionManager>();
        var eventAggregatorMock = new Mock<IEventAggregator>();
        var shellControllerMock = new Mock<IShellController>();
        var plantTreeNodeSelectedEventMock = new Mock<PlantTreeNodeSelectedEvent>();

        plantTreeViewMock.Setup(v => v.Model).Returns(plantTreePresentationModel.Object);
        container.RegisterInstance<IPlantTreePresentationModel>(plantTreePresentationModel.Object);
        regionManagerMock.Setup(o => o.Regions[RegionNames.NavigationRegion]).Returns(navRegionMock.Object);
        navRegionMock.Setup(r => r.GetView(typeof(IPlantTreeView).Name)).Returns(plantTreeViewMock.Object);
        navRegionMock.Setup(r => r.Activate(plantTreeViewMock.Object));
        plantTreePresentationModel.SetupSet(m => m.LastRefreshDateTime);
        eventAggregatorMock.Setup(a => a.GetEvent<PlantTreeNodeSelectedEvent>()).Returns(plantTreeNodeSelectedEventMock.Object);


        //Setup container.
        container.RegisterType<IPlantTreeController, PlantTreeController>();
        container.RegisterInstance<IPlantTreePresentationModel>(plantTreePresentationModel.Object);
        container.RegisterInstance<IPlantTreeView>(plantTreeViewMock.Object);
        container.RegisterInstance<IRegion>(navRegionMock.Object);
        container.RegisterInstance<IPlantTreeModule>(plantTreeModuleMock.Object);
        container.RegisterInstance<IRegionManager>(regionManagerMock.Object);
        container.RegisterInstance<IEventAggregator>(eventAggregatorMock.Object);
        container.RegisterInstance<IShellController>(shellControllerMock.Object);
        container.RegisterInstance<PlantTreeNodeSelectedEvent>(plantTreeNodeSelectedEventMock.Object);


        //Initialize controller to be tested.
        IPlantTreeController controllerToTest = container.Resolve<IPlantTreeController>();

        controllerToTest.ShowPlantTreeView();


        //Test if controller interacted with the mocks as expected.
        plantTreePresentationModel.VerifyAll();
        regionManagerMock.VerifyAll();
        navRegionMock.VerifyAll();
    }

有更好的方法来测试我的课程吗?任何意见,将不胜感激。


我自己也遇到过这个问题,其中的类有很多依赖项。确实没有什么办法可以解决这个问题。

您的方法真的依赖于所有这些类吗?我只看到这里使用了两个或三个依赖项(IRegionManager、IPlantTreePresentationModel)。这些应该是你唯一的have模拟来测试你的方法。您可以使用一组适合您的测试的依赖项来测试它,而不是适合该对象的任何测试。

您可能要考虑的另一件事是您可以将多少个依赖项纳入测试的启动代码(用 [TestInitialize] 修饰的方法)。一些常见的依赖项和容器可能存在于整个测试套件的范围内,特别是如果它们在每次测试时都不会更改的话。

依赖注入确实会让您的生活变得更轻松,即使您没有意识到这一点。我发现很多进行“单元测试”的人并没有真正正确地进行测试,而是由于他们没有与应用程序的其他部分进行适当的隔离而进行功能测试。

依赖注入几乎迫使您进入一个模型,在该模型中您能够将实际想要测试的代码与应用程序的所有其他部分完全隔离。它可能会花费一些前期费用,但是单元测试的质量以及从单元测试中获得的反馈的粒度将超过这些成本,特别是当您进入应用程序生命周期的后期并开始重构时。到时候你会感谢自己的。坚持下去。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Composite WPF (Prism) 中,我应该如何对我的控制器进行单元测试? 的相关文章

随机推荐

  • Shiny 中的模态对话框:可以调整宽度但不能调整高度

    在我的 Shiny 应用程序中 我有几个来自闪亮BS 包的模式窗口 我可以像这样调整这些模式窗口的宽度 tags head tags style HTML modal lg width 1200px abs 1 background col
  • 是一对一的关系不好的策略

    用户始终拥有一个钱包 一个钱包始终属于一位用户 由于我想分离与钱夹相关的属性 我创建了 Wallet 对象并能够跟踪钱交易 我创建了 public Wallet Entity
  • Hibernate 命名查询使用 Like 和 % % 运算符?

    在我的 Hibernate JPA 示例代码中 public List
  • 使用抽象类作为模板类型

    我对c 还是很陌生 来自java 我有一个 stl 类型列表Actor When Actor仅包含 真实 方法就没有问题 我现在想将这个类扩展到几个类 并且需要将一些方法更改为抽象的 因为它们不再具有具体的意义 正如我 从文档中 预期的那样
  • Java分数计算器

    我对 Java 编程还很陌生 我的 AP 计算机编程课程有作业要完成 所以请耐心等待 我必须弄清楚如何将两个分数相乘 我想知道是否有任何方法可以在方法内部声明变量并在该方法外部使用它 我在介绍方法中的 while 循环 谢谢您 希望这不会令
  • 如何阻止gradle每次都下载

    我已经在 Ubuntu 16 04 中安装了 gradle 这是输出gradle v Gradle 2 10 Build time 2016 01 26 15 17 49 UTC Build number none Revision UNK
  • 实体框架中对象属性中的 NULL 值

    Tables Article Author Comment 1篇文章和1位作者可以有 评论 数据库中有 1 篇文章 1 位作者和 1 条评论 问题是 该代码 myBD my bd new myBD var articles by bd Ar
  • 系数函数速度慢

    请考虑 Clear x expr Sum x i i 15 30 CoefficientList expr x Timing Coefficient Expand expr x 234 Timing Coefficient expr x 2
  • 类型错误:“生成器”对象没有属性“__getitem__”

    我编写了一个应该返回字典的生成函数 但是当我尝试打印字段时出现以下错误 print row2 SearchDate TypeError generator object has no attribute getitem 这是我的代码 fro
  • numpy.nan_to_num - 'nan' 关键字无法识别

    当您尝试使用以下代码将 nan 值替换为自定义数值时 np nan to num exp allowance nan 9999 99 它产生以下错误 typeerror nan to num got an unexpected keywor
  • 丰富:数据表行跨度问题

    我需要创建一个 rich dataTable 甚至扩展 具有以下功能 我有一个公司类 其中包含产品对象的集合 我想展示下表 我仍然没有弄清楚如何使用子表执行此操作 在所有示例中 我发现子表具有与主表完全相同的列 据推测 我需要在前两列中使用
  • 如何使用 Swift 将文本复制到剪贴板/粘贴板

    我正在寻找一个干净的示例 说明如何将文本复制到 iOS 剪贴板 然后可以在其他应用程序中使用 粘贴 该功能的好处是可以快速复制文本 无需传统文本复制的标准文本突出显示功能 我假设关键课程位于UIPasteboard 但在中找不到相关区域他们
  • 使用 Spring Batch 将文件中的日期解析为 LocalDateTime

    我正在尝试使用 Spring Batch 读取包含日期的 CSV 文件 但在将日期解析为LocalDateTime Object 字段 日期 上的对象 目标 中的字段错误 拒绝值 2017 07 20 04 15 25 0 代码 typeM
  • Java:如何检测(并更改?)System.console 的编码?

    我有一个在控制台上运行的程序 其变音符号和其他特殊字符在 Mac 上以 的形式输出 这是一个简单的测试程序 public static void main String args System out println h h System
  • Mongoose - 遍历对象

    在 node js 上使用 mongoose 我试图找到玩家 game players id 等于我传递的 id 的所有游戏 Schema var Game mongoose Schema id String date type Date
  • Eclipse CDT C++20 支持

    有没有办法在 Eclipse 2020 03 CDT 9 11 中启用对 C 20 功能的支持 我的意思是摆脱不正确的语法突出显示 例如忽略新添加的关键字 如 concept requires 以及 C 20 标准中定义的其他关键字 我有一
  • 如何获取 res.drawable 文件夹的路径来复制文件?

    我正在编写我的应用程序AndroidStudio 我的里面有gif文件drawable gifs文件夹 我希望将该文件复制到MediaStore Images Media单击按钮后的文件夹 目前 即使使用发布的一些答案 我也无法获取我的 g
  • 将 NULL 传递给 SSRS URL 访问参数?

    使用 URL 访问将参数传递给 SSRS 报告时如何指定 NULL 值 即当使用表格时 http server ReportServer Pages ReportViewer aspx Report Parameter value 使用语法
  • selenium 没有找到合适的方法,直到(ExpectedCondition)

    这是有线的问题 我导入的项目运行 100 几个月前 今天我已将其与依赖项一起导入 但存在问题WebDriverWait 这是我的代码 WebDriverWait driverWait new WebDriverWait driver 100
  • 在 Composite WPF (Prism) 中,我应该如何对我的控制器进行单元测试?

    我正在使用一个模块构建一个基本的复合 WPF Shell 我想对我的模块进行单元测试 显然 Composite WPF 以一种易于单元测试的方式模块化我的代码 下面是我想要进行单元测试的代码 它驻留在我的模块的控制器中 请注意标准复合 WP