【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版)』参照