【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版)》
【MVC5】First Unit Test的更多相关文章
- 【MVC5】画面多按钮提交
画面上有个多个按钮时,如何绑定到各自的Action上? 1.追加如下MultipleButtonAttribute类 1 using System; 2 using System.Reflection ...
- 【MVC5】对MySql数据库使用EntityFramework
版本: MySql : 5.6.3 MySql.Data : 6.9.7 MVC : 5 EntityFramework : 6.1.3 VS : 2015 步骤: 1.安装[mysql-connec ...
- 【MVC5】使用域用户登录+记住我
1.配置Web.config文件 添加域链接字符串 <connectionStrings> <add name="ADConnectionString" conn ...
- 【MVC5】使用权限+角色
1.在Ticket中设置用户角色 在权限的Ticket中设置用户的角色(这里是逗号分割). List<string> roles = new List<string>(); i ...
- 【MVC5】后台修改的Model值反映不到客户端的问题
画面上的检索结果有翻页功能,就在画面上追加了几个隐藏控件保存上次检索时的检索条件. 检索时更新这些隐藏控件的值,Debug时确实把Model中对应的属性值变掉了,但是到了客户端又变回之前的值了. 百思 ...
- 【MVC5】日期选择控件DatePicker
项目中使用了Bootstrap,日期控件就选择了依赖于bootstrap的DatePicker. 在App_Start\BundleConfig.cs中引用css和js文件: bundles.Add( ...
- 【MVC5】First AngularJS
※本文参照<ASP.NET MVC 5高级编程(第5版)> 1.创建Web工程 1-1.选择ASP.NET Web Application→Web API 工程名为[atTheMovie] ...
- 【t033】单位unit
Time Limit: 1 second Memory Limit: 64 MB [问题描述] 某星球上有很多计量系统,之间的计量单位的转换很繁琐.希望你能编程解决这个问题. 现有N (1 <= ...
- 【MVC5】ASP.NET MVC 项目笔记汇总
ASP.NET MVC 5 + EntityFramework 6 + MySql 先写下列表,之后慢慢补上~ 对MySql数据库使用EntityFramework 使用域用户登录+记住我 画面多按钮 ...
随机推荐
- bzoj4897 [Thu Summer Camp2016]成绩单
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4897 [题解] 第一次看这题想的是f[l,r]的区间dp发现仅记录这两个好像不能转移啊 会出 ...
- IOS-使用CAShapLayer绘制扇形
IOS-使用CAShapLayer绘制扇形 为了增加应用体验感,我们动态绘制扇形或者饼状图效果. 这里我们使用CAShapeLayer,这样就不必再-(void)draw函数内绘制图形 参考代码 -( ...
- 学习ExtJS4 常用控件
ExtJS组件配置方式介绍 1.使用逗号分隔参数列表配置组件 首先来看一个简单的逗号分隔参数列表的例子.这个例子非常简单,它用来显示信息提示框. 2.使用Json对象配置组件 接下来看一个使用 ...
- STM in Haskell
Software Transactional Memory,软件事务内存管理(应该是这么翻译的吧T_T) 类似于数据库的事务,所有的操作都有log,最后验证其他线程是否对数据进行修改,要是有那么就回滚 ...
- python的加密操作
hashlib加密 import hashlib # 有很多种加密方式,md5,sha1等等 h = hashlib.md5() # 提交加密的内容,bytes形式 h.update(b"s ...
- 阿里的iptables,保存一份
# Generated by iptables-save v1.4.7 on Fri Apr 14 16:37:31 2017 *filter :INPUT ACCEPT [0:0] :FORWARD ...
- HDU 2544.最短路-最短路(Dijkstra)
本来不想写,但是脑子不好使,还是写一下备忘_(:з」∠)_ 最短路 Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/3276 ...
- 数论day1 —— 基础知识(们)
[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61632537 向大(hei)佬(e)势力学(di ...
- manacher(马拉车)算法详解+例题一道【bzoj3790】【神奇项链】
[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=39091399 (CSDN好像有bug,不知道为什 ...
- linux-配置字符串-grep
grep -rn "hello,world!" * * : 表示当前目录所有文件,也可以是某个文件名 -r 是递归查找 -n 是显示行号 -R 查找所有文件包含子目录 -i 忽略大 ...