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版)》

【MVC5】First Unit Test的更多相关文章

  1. 【MVC5】画面多按钮提交

    画面上有个多个按钮时,如何绑定到各自的Action上? 1.追加如下MultipleButtonAttribute类 1 using System; 2 using System.Reflection ...

  2. 【MVC5】对MySql数据库使用EntityFramework

    版本: MySql : 5.6.3 MySql.Data : 6.9.7 MVC : 5 EntityFramework : 6.1.3 VS : 2015 步骤: 1.安装[mysql-connec ...

  3. 【MVC5】使用域用户登录+记住我

    1.配置Web.config文件 添加域链接字符串 <connectionStrings> <add name="ADConnectionString" conn ...

  4. 【MVC5】使用权限+角色

    1.在Ticket中设置用户角色 在权限的Ticket中设置用户的角色(这里是逗号分割). List<string> roles = new List<string>(); i ...

  5. 【MVC5】后台修改的Model值反映不到客户端的问题

    画面上的检索结果有翻页功能,就在画面上追加了几个隐藏控件保存上次检索时的检索条件. 检索时更新这些隐藏控件的值,Debug时确实把Model中对应的属性值变掉了,但是到了客户端又变回之前的值了. 百思 ...

  6. 【MVC5】日期选择控件DatePicker

    项目中使用了Bootstrap,日期控件就选择了依赖于bootstrap的DatePicker. 在App_Start\BundleConfig.cs中引用css和js文件: bundles.Add( ...

  7. 【MVC5】First AngularJS

    ※本文参照<ASP.NET MVC 5高级编程(第5版)> 1.创建Web工程 1-1.选择ASP.NET Web Application→Web API 工程名为[atTheMovie] ...

  8. 【t033】单位unit

    Time Limit: 1 second Memory Limit: 64 MB [问题描述] 某星球上有很多计量系统,之间的计量单位的转换很繁琐.希望你能编程解决这个问题. 现有N (1 <= ...

  9. 【MVC5】ASP.NET MVC 项目笔记汇总

    ASP.NET MVC 5 + EntityFramework 6 + MySql 先写下列表,之后慢慢补上~ 对MySql数据库使用EntityFramework 使用域用户登录+记住我 画面多按钮 ...

随机推荐

  1. bzoj4897 [Thu Summer Camp2016]成绩单

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4897 [题解] 第一次看这题想的是f[l,r]的区间dp发现仅记录这两个好像不能转移啊 会出 ...

  2. IOS-使用CAShapLayer绘制扇形

    IOS-使用CAShapLayer绘制扇形 为了增加应用体验感,我们动态绘制扇形或者饼状图效果. 这里我们使用CAShapeLayer,这样就不必再-(void)draw函数内绘制图形 参考代码 -( ...

  3. 学习ExtJS4 常用控件

    ExtJS组件配置方式介绍 1.使用逗号分隔参数列表配置组件    首先来看一个简单的逗号分隔参数列表的例子.这个例子非常简单,它用来显示信息提示框. 2.使用Json对象配置组件  接下来看一个使用 ...

  4. STM in Haskell

    Software Transactional Memory,软件事务内存管理(应该是这么翻译的吧T_T) 类似于数据库的事务,所有的操作都有log,最后验证其他线程是否对数据进行修改,要是有那么就回滚 ...

  5. python的加密操作

    hashlib加密 import hashlib # 有很多种加密方式,md5,sha1等等 h = hashlib.md5() # 提交加密的内容,bytes形式 h.update(b"s ...

  6. 阿里的iptables,保存一份

    # Generated by iptables-save v1.4.7 on Fri Apr 14 16:37:31 2017 *filter :INPUT ACCEPT [0:0] :FORWARD ...

  7. HDU 2544.最短路-最短路(Dijkstra)

    本来不想写,但是脑子不好使,还是写一下备忘_(:з」∠)_ 最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/3276 ...

  8. 数论day1 —— 基础知识(们)

    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61632537 向大(hei)佬(e)势力学(di ...

  9. manacher(马拉车)算法详解+例题一道【bzoj3790】【神奇项链】

    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=39091399 (CSDN好像有bug,不知道为什 ...

  10. linux-配置字符串-grep

    grep -rn "hello,world!" * * : 表示当前目录所有文件,也可以是某个文件名 -r 是递归查找 -n 是显示行号 -R 查找所有文件包含子目录 -i 忽略大 ...