【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 使用域用户登录+记住我 画面多按钮 ...
随机推荐
- codeforce 570 problem E&& 51Nod-1503-猪和回文
1503 猪和回文 一只猪走进了一个森林.很凑巧的是,这个森林的形状是长方形的,有n行,m列组成.我们把这个长方形的行从上到下标记为1到n,列从左到右标记为1到m.处于第r行第c列的格子用(r,c)表 ...
- panel(NOIP模拟赛Round 4)
好吧,,这道题..本来以为挺难的.打了个暴力bfs+hash(期望得分30,实际得分30) 奇特的是,这道题如果不用hash(期望得分20,实际得分100),好吧数据实在是太水了(不会T吗?) 然后我 ...
- Android Handler使用
1. 介绍 Handler允许向关联线程的消息队列(MessageQueue)发送消息(Message)和可执行对象(Runnable).每个Handler实例都与某个线程(即创建该Handler的线 ...
- popen的用法及与system调用的区别
首先用man查看下popen的介绍: popen(3) - Linux man page Name popen, pclose - pipe stream to or from a process S ...
- Appium+python自动化11-adb必知必会的几个指令【转载】
前言 学android测试,adb是必学的,有几个常用的指令需要熟练掌握 一.检查设备 1.如何检查手机(或模拟器)是连上电脑的,在cmd输入: >adb devices
- HDU 1171.Big Event in HDU-动态规划0-1背包
Big Event in HDU Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- Python的程序结构[2] -> 类/Class[0] -> 类的特殊属性
类的特殊属性 / Special Property of Class Python 中通过 class 进行类的定义,类可以实例化成实例并利用实例对方法进行调用. 类中还包含的一些共有的特殊属性. 特 ...
- HDU 3237 Tree(树链剖分)(线段树区间取反,最大值)
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 9123 Accepted: 2411 Description ...
- PMBOK及PMP考试精要
PROJECT MANAGEMENT KNOWLEDGE AREAS项目管理知识体系 2 PROJECT LIFE CYCLE / PROJECT MANAGEMENT PROCESS GROUPS项 ...
- Binary Tree Iterative Traversal
Preorder class Solution { public: vector<int> preorderTraversal(TreeNode* root) { vector<in ...