【MVC5】First Unit Test
19444 ワード
1.コントローラテスト
注意点:
1.コントローラにビジネスロジックを含まない
2.コンストラクション関数によるサービス依存性の伝達
例:MathControllerにAddのアクションがある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);
}
}
偽サービスを作成し、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では2つの値の合計はありません.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版)』参照
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();
}
}
}
namespace FirstUnitTest.Services
{
public interface IMathService
{
int Add(int left, int right);
}
}
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;
}
}
}
[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);
}
[TestMethod]
public void RedirectToAdd()
{
SpyMathService service = new SpyMathService();
MathController controller = new MathController(service);
RedirectToRouteResult result = controller.Index();
Assert.AreEqual("Add", result.RouteValues["action"]);
}
デフォルト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版)』参照
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;
}
}
}
}