你的位置:首页 > ASP.net教程

[ASP.net教程]【MVC5】First Unit Test


1.控制器测试

注意点:

    1.控制器中不要包含业务逻辑

    2.通过构造函数传递服务依赖

例:MathController中有一个Add的Action

using FirstUnitTest.Services;using System.Web.Mvc;namespace FirstUnitTest.Controllers{  public class MathController : Controller  {    IMathService _service;    public MathController(IMathService service) {      _service = service;    }    // GET: Math    public RedirectToRouteResult Index()    {      return RedirectToAction("Add");      //return View();    }    [HttpGet]    public ActionResult Add()    {      return View();    }    [HttpPost]    public ViewResult Add(int left, int right)    {      ViewBag.Result = _service.Add(left, right);      return View();    }  }}

IMathService定义如下,很显然是个求和方法:

namespace FirstUnitTest.Services{  public interface IMathService  {    int Add(int left, int right);  }}

编写一个假Service,给Controller提供一个假的业务逻辑层。

using FirstUnitTest.Services;namespace FirstUnitTest.Tests.Services{  public class SpyMathService : IMathService  {    public int Add_Left;    public int Add_Right;    public int Add_Result;        public int Add(int left, int right)    {      Add_Left = left;      Add_Right = right;      return Add_Result;    }  }}

注意:上面的SpyService中没有对两个值求和,因为我们只关注MathService的Input和Output(Input就是left和right参数,Output就是返回值)。

测试方法:

[TestMethod]public void AddUseMathService(){  SpyMathService service = new SpyMathService() { Add_Result = 42 };  MathController controller = new MathController(service);  ViewResult result = controller.Add(4, 12);  Assert.AreEqual(service.Add_Result, result.ViewBag.Result);  Assert.AreEqual(4, service.Add_Left);  Assert.AreEqual(12, service.Add_Right);}

Redirect测试(上面MathController中的Index Action):

[TestMethod]public void RedirectToAdd(){  SpyMathService service = new SpyMathService();  MathController controller = new MathController(service);  RedirectToRouteResult result = controller.Index();  Assert.AreEqual("Add", result.RouteValues["action"]);}

2.路由测试

默认MVC项目的路由如下:

using System.Web.Mvc;using System.Web.Routing;namespace FirstUnitTest{  public class RouteConfig  {    public static void RegisterRoutes(RouteCollection routes)    {      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");      routes.MapRoute(        name: "Default",        url: "{controller}/{action}/{id}",        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }      );    }  }}

测试方法:

using Microsoft.VisualStudio.TestTools.UnitTesting;using Moq;using System.Web;using System.Web.Mvc;using System.Web.Routing;namespace FirstUnitTest.Tests.Routes{  [TestClass]  public class RouteTest  {    /// <summary>    /// 测试IngoreRoute函数调用    /// </summary>    [TestMethod]    public void RouteForEmbeddedResource()    {      // Arrange      var mockContext = new Mock<HttpContextBase>();      mockContext.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath)        .Returns("~/handler.axd");      var routes = new RouteCollection();      //MvcApplication.RegisterRoutes(routes);      RouteConfig.RegisterRoutes(routes);      // Act      RouteData routeData = routes.GetRouteData(mockContext.Object);      // Assert      Assert.IsNotNull(routeData);      Assert.IsInstanceOfType(routeData.RouteHandler, typeof(StopRoutingHandler));    }    /// <summary>    /// 测试MapRoute函数调用    /// </summary>    [TestMethod]    public void RouteToHomePae()    {      // Arrange      var mockContext = new Mock<HttpContextBase>();      mockContext.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath)        .Returns("~/");      var routes = new RouteCollection();      RouteConfig.RegisterRoutes(routes);      // Act      RouteData routeData = routes.GetRouteData(mockContext.Object);      // Assert      Assert.IsNotNull(routeData);      Assert.AreEqual("Home", routeData.Values["controller"]);      Assert.AreEqual("Index", routeData.Values["action"]);      Assert.AreEqual(UrlParameter.Optional, routeData.Values["id"]);    }    // 不需要对不匹配路由编写测试代码  }}

使用Mock需要安装Moq包(需要设定ProjectName参数,否则会默认安装到Web工程)

Install-Package moq -ProjectName FirstUnitTest.Tests

3.验证测试

Movie模型:

using System.ComponentModel.DataAnnotations;using System.Data.Entity;namespace FirstUnitTest.Models{  public class Movie  {    public int Id { get; set; }    [Required]    public string Title { get; set; }    [Required]    [Range(1920, 2015)]    public int ReleaseYear { get; set; }    public int RunTime { get; set; }  }  public class MovieDb : DbContext  {    public DbSet<Movie> Movies { get; set; }  }}

属性验证:

using System;using Microsoft.VisualStudio.TestTools.UnitTesting;using FirstUnitTest.Models;using System.ComponentModel.DataAnnotations;namespace FirstUnitTest.Tests.Validation{  [TestClass]  public class MovieValidationTest  {    [TestMethod]    public void TitleRequireTest()    {      System.Threading.Thread.CurrentThread.CurrentUICulture         = new System.Globalization.CultureInfo("zh-cn");      Movie movie = new Movie();      ValidationContext context = new ValidationContext(movie, null, null) {        DisplayName = "Title",        MemberName = "Title",      };      RequiredAttribute validator = new RequiredAttribute();      try      {        validator.Validate(movie.Title, context);      }      catch (ValidationException ex)      {        // 错误消息的语言由当前线程的CurrentUICulture决定        Assert.AreEqual("Title 字段是必需的。", ex.Message);        //throw;      }    }  }}

※本文参照《ASP.NET MVC 5高级编程(第5版)》