为MVC模块创建一个单元测试

概述

因为MVC控制器是MVC的核心业务逻辑模块,这是一个最佳实践创建自动化单元测试,以确保他们的行为。这个例子演示了如何创建一个单元测试模块的MVC控制器。

注意:这个单元测试过程只适用于模块用款MVC模块创建的模板。

先决条件

  • 使用MVC模块款模板创建的模块在Visual Studio项目模板。
  • Moq,模拟c# / . net框架。

步骤

  1. 添加一个新的单元测试项目MVC模块解决方案。
    1. 在Visual Studio的解决方案资源管理器,右键点击你的MVC模块解决方案和选择添加>新项目

      添加新项目

    2. 添加新项目对话框中,选择单元测试项目输入一个名称,并选择本地文件夹来存储。

      创建单元测试项目

  2. 添加必要的MVC和组装款引用。

    每个组件添加到新的单元测试项目中,右键单击项目引用节点和添加一个装配参考。


    项目参考

    添加下面的程序集的引用,以及其他模块具体需求:

    • DotNetNuke
    • DotNetNuke.Web.Mvc
    • System.Web.Mvc
  3. (可选)使用Moq模拟数据存储。

    Moq是一个为c# /仿真框架。净,通常用于单元测试快速创建依赖对象,模拟实际的对象。这个项目使用Moq来模拟一个ItemManager对象以运行测试而不需要一个数据库。

    注意:示例测试这一步不是必需的,但它需要在大多数实际测试用例。
    1. 在Visual Studio的解决方案资源管理器,右键单击您的单元测试项目。
    2. 选择Nuget包管理
    3. 寻找Moq并安装。

      Moq Nuget安装

    这个示例创建了一个MockStores类使用Moq模拟数据库及其行为。

    创建一个文件夹叫模拟并创建一个MockStores.cs文件在文件夹中。输入以下代码MockStores.cs:

    使用System.Collections.Generic;使用来;使用Dnn.Modules.CompanyName.MyMvcModule.Components;使用Dnn.Modules.CompanyName.MyMvcModule.Models;使用Moq;名称空间MyMvcModuleTests。模拟{ class MockStores { public static Mock MockItemManager() { var allItems = new List(); var mock = new Mock(); // void CreateItem(Item t); mock.Setup(x => x.CreateItem(It.IsAny())) .Callback((Item i) => { allItems.Add(i); }); // void DeleteItem(int itemId, int moduleId); mock.Setup(x => x.DeleteItem(It.IsAny(), It.IsAny())) .Callback((int id, int mid) => { var remItem = allItems.FirstOrDefault(i => i.ItemId == id && i.ModuleId == mid); allItems.Remove(remItem); }); // void DeleteItem(Item t); mock.Setup(x => x.DeleteItem(It.IsAny())) .Callback((Item di) => { var remItem = allItems.FirstOrDefault(i => i.ItemId == di.ItemId); allItems.Remove(remItem); }); // IEnumerable GetItems(int moduleId); mock.Setup(x => x.GetItems(It.IsAny())) .Returns((int mid) => allItems.Where(x => x.ModuleId == mid)); // Item GetItem(int itemId, int moduleId); mock.Setup(x => x.GetItem(It.IsAny(), It.IsAny())) .Returns((int id, int mid) => allItems.FirstOrDefault(i => i.ItemId == id && i.ModuleId == mid)); // void UpdateItem(Item t); mock.Setup(x => x.UpdateItem(It.IsAny())) .Callback((Item i) => { allItems.Add(i); }); return mock; } } }

    静态MockItemManager ()方法MockStores模拟类的所有方法IItemManager实现。因此,MockStores可用于控制器的IItemManager实现。

    allItems变量是一个通用的列表对象和作为数据存储。

  4. 创建单元测试。
    提示:单元测试方法名称应该比典型的更具描述性的方法。理想情况下,测试方法名称包括被测试的方法的名称,测试执行和预期的结果。例子:Edit_CreateNewItem_ModuleIdAssignedinModel可能是测试方法的名称,如果一个验证编辑()方法创建一个新项(如果还不存在)项检查,如果moduleID被分配在视图的模型中。

    这个示例创建一个单元测试的ItemController类。

    您可以重命名示例单元测试文件UnitTest1.cs(包括作为默认创建新的单元测试项目时)ItemControllerTests.cs或者创建一个新文件。然后输入下面的代码ItemControllerTests.cs:

    使用System.Web.Mvc;使用Dnn.Modules.CompanyName.MyMvcModule.Controllers;使用Dnn.Modules.CompanyName.MyMvcModule.Models;使用Microsoft.VisualStudio.TestTools.UnitTesting;使用MyMvcModuleTests.Mocks;名称空间MyMvcModuleTests {(TestClass)公共类ItemControllerTests {(TestMethod)公共空Edit_CreateNewItem_ModuleIdAssignedinModel(){/ / 1 -安排int moduleId = 2;var mockData = MockStores.MockItemManager ();var modTwoItemCntrl = new ItemController (mockData。对象,moduleId);/ /创建一个控制器模块的moduleId = 2。/ / 2 - var actionResult行动= (ViewResult) modTwoItemCntrl.Edit (); // Call the edit view with no item Id (Add New). // 3 - Assert var itemModel = (Item)actionResult.Model; Assert.IsTrue(itemModel != null && itemModel.ModuleId == moduleId); } } }
    这个示例单元测试使用单元测试的安排行动维护模式:
    • 安排:一个新实例ItemController创建一个新的MockStores.MockItemManager实例和moduleId。(下一步改造ItemController构造函数与这个单元测试工作。
    • 行动:编辑()控制的方法叫做没有任何参数,并保存结果。
    • 断言:测试验证moduleId在结果视图中设置模块添加/编辑项目视图呈现之前。

    如果你的控制器有更复杂的业务逻辑,可以自动化单元测试的验证。

  5. 翻新的ItemController.Edit ()使用单元测试方法。

    在代码中使用MVC模块生成模板ItemController没有依赖项注入能力的数据层。此外,一些基本款环境对象,如PortalSettingsModuleContext运行单元测试时不可用。改造的ItemController.Edit ()方法修复这些限制。

    这个示例添加一个构造函数和类变量ItemController注入的IItemManager实现/模拟器和moduleId

    公共ActionResult编辑(int itemId = 1){/ /忽略登记错误的单元测试。尝试{DotNetNuke.Framework.JavaScriptLibraries.JavaScript.RequestRegistration (CommonJs.DnnPlugins);}catch{}如果(PortalSettings ! = null) {var userlist = UserController.GetUsers (PortalSettings.PortalId);var用户从用户userlist.Cast = <用户信息> ().ToList()选择新的SelectListItem{文本=用户。DisplayName, Value = user.UserID.ToString ()};ViewBag。用户=用户;}如果(ModuleContext ! = null) {_moduleId = ModuleContext.ModuleId;}var项= (itemId = = 1) ?新项目ModuleId = _moduleId} {: ItemManager.Instance。GetItem (itemId _moduleId);返回视图(项); }

    一些线路在默认ItemController不适用这个示例单元测试中,它使用一个吗ItemController模拟。

    忽视这些线路在运行单元测试,改进ItemController.Edit ()方法检查PortalSettingsModuleContext,从模块的运行时引擎得到他们的价值观。在单元测试期间,绕过了运行时引擎ItemController模拟;因此,将这些变量当单元测试运行。

    _moduleId变量传递给构造函数的itemId示例单元测试和ItemManager参数。实例将是我们模拟实例,因为我们推翻了在构造函数中实现单元测试。

  6. 运行单元测试。
    你可以在Visual Studio中运行单元测试:
    • 测试>调试
    • 测试>运行

    测试资源管理器窗口给你快速查看所有的测试,测试结果,和命令来运行它们。


    测试资源管理器

    对于更高级的用户,可以自动调度运行单元测试作为构建过程的一部分。