• asp.net 单元测试(转)


    最早接触单元测试是看了极限编程相关资料里边讲的测试驱动开发,然后下载了Nunit研究了一下,但并没产生多大的触动,因为那个时候做的都是些时间紧任务重的事情,对于单元测试的直接感觉就是有可能比较费时间。直到看了《敏捷软件开发:原则、模式与实践》,里边那个保龄球计分程序很精彩,让我知道了保龄球原来是这么计分的,更重要的是让我认识到测试驱动编程原来这样有意义,并且其实并不浪费时间(至于测试驱动编程到底有意义在哪里,我这里就不说了,大家可以参阅Kent的《测试驱动开发》,Robert C. Martin的《敏捷软件开发:原则、模式与实践》,http://www.ibm.com/developerworks/cn/linux/l-tdd/http://www.ibm.com/developerworks/cn/java/j-xp042203/等)。在webform中对web层的逻辑很难做单元测试(当然我们可以利用mvp模式(参考:http://www.cnblogs.com/bluewater/archive/2006/12/11/589214.html#1219888)来分解web层逻辑,但因为没有框架的支持,并且实现起来也不是很简单,也不是特别好理解,所以应用并不广泛)。ASP.NET MVC很好的解决了测试web逻辑的问题,可测试性也变成了ASP.NET MVC的优势之一。下面我们就来介绍一下如何在ASP.NET MVC中进行单元测试。

    一、测试路由器:

    我们首先利用mvc的模板创建一个解决方案,我们可以在Gloabal.asax.cs文件中发现如下代码

     public class MvcApplication : System.Web.HttpApplication
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
                routes.MapRoute(
                    "Default",                                              // Route name
                    "{controller}/{action}/{id}",                           // URL with parameters
                    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
                );
    
            }

    下面我们就为这段代码写一个单元测试(如果对路由还不清楚请参见:ASP.NET MVC实践系列1-UrlRouting )

     1         [TestMethod]
     2         public void TestMvcApplicationRoute()
     3         {
     4             RouteCollection routes = new RouteCollection();
     5             MvcApplication.RegisterRoutes(routes);
     6             var httpContextMock = new Mock<HttpContextBase>();
     7             httpContextMock.Setup(c => c.Request
     8                 .AppRelativeCurrentExecutionFilePath).Returns("~/Home/Index");
     9 
    10             RouteData routeData = routes.GetRouteData(httpContextMock.Object);
    11 
    12             Assert.IsNotNull(routeData, "Should have found the route");
    13             Assert.AreEqual("Home", routeData.Values["Controller"]);
    14             Assert.AreEqual("Index", routeData.Values["action"]);
    15             Assert.AreEqual("", routeData.Values["id"]);
    16         }

    下面我们解释一下上面的代码

    RouteCollection routes = new RouteCollection();
    MvcApplication.RegisterRoutes(routes);

    这两行的意思是将routes按照默认路由代码中的格式生成相应的路由。

    var httpContextMock = new Mock<HttpContextBase>();
    httpContextMock.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath).Returns("~/Home/Index");

    这两行的意思是创建一个HttpContextBase的mock类,这里我们使用的是MoQ框架来生成mock类(参见:MoQ(基于.net3.5,c#3.0的mock框架)简单介绍 )。

    RouteData routeData = routes.GetRouteData(httpContextMock.Object);

    这行的意思是从routes中获得路由数据,为下边断言路由中的内容作准备。

    Assert.AreEqual("Home", routeData.Values["Controller"]);
    Assert.AreEqual("Index", routeData.Values["action"]);
    Assert.AreEqual("", routeData.Values["id"]);

    这三行分别验证了路由中生成的Controller,action,id的正确性。

    二、测试Controller与Action

    1、测试ViewData

    我们先来看一下ASP.NET MVC的默认模板中的测试代码:

       public ActionResult Index()
            {
                ViewData["Message"] = "Welcome to ASP.NET MVC!";
                
                return View();
            }
    
    //测试代码
     [TestMethod]
            public void Index()
            {
                // Arrange
                HomeController controller = new HomeController();
    
                // Act
                ViewResult result = controller.Index() as ViewResult;
    
                // Assert
                ViewDataDictionary viewData = result.ViewData;
                Assert.AreEqual("Welcome to ASP.NET MVC!", viewData["Message"]);
            }

    我们可以在测试代码中对viewData的内容进行验证,一般并不推荐使用弱类型的viewData来进行传递数据,下面我们来看一下如何来测试viewModel中的内容。

    public ActionResult About()
            {
                News news = new News() { ID = 1, Author = "lfm" };
                return View(news);
            }
    
    测试代码
    
    [TestMethod]
            public void About()
            {
                // Arrange
                HomeController controller = new HomeController();
                
                // Act
                ViewResult result = controller.About() as ViewResult;
                Assert.AreEqual(1, ((News)result.ViewData.Model).ID);
                // Assert
                Assert.IsNotNull(result);
            }

    2、测试RedirectToAction:

     public ActionResult TestRedirectToAction()
            {
                return RedirectToAction("Index");
            }
    
    //测试代码
    
    [TestMethod]
            public void TestRedirectToAction()
            {
                // Arrange
                HomeController controller = new HomeController();
    
                // Act
                var result = controller.TestRedirectToAction() as RedirectToRouteResult; ;
    
                // Assert
                Assert.IsNotNull(result);
                Assert.AreEqual("Index", result.RouteValues["action"]);
            }

    三、测试View Helpers

    我们常常会把一些牵扯到逻辑的View代码写到Helper中,所以测试Helper非常有意义,我们先写一个简单的Helper

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Web.Mvc;
     4 public static class MyHelpers
     5 {
     6     public static string UnorderedList<T>(this HtmlHelper html, IEnumerable<T> items)
     7     {
     8         if (html == null)
     9         {
    10             throw new ArgumentNullException("html");
    11         }
    12         string ul = "<ul>";
    13         foreach (var item in items)
    14         {
    15             ul += "<li>" + html.Encode(item.ToString()) + "</li>";
    16         }
    17         return ul + "</ul>";
    18     }
    19 }

    这个Helper的完成的工作是将输入的集合数据分解然后按列表输出。

     1 [TestMethod]
     2         public void TestHelp()
     3         {
     4             var contextMock = new Mock<HttpContextBase>();
     5             var controllerMock = new Mock<ControllerBase>();
     6             var view = new Mock<IView>();
     7             var cc = new ControllerContext(contextMock.Object, new RouteData(), controllerMock.Object);
     8             var viewContext = new ViewContext(cc, view.Object, new ViewDataDictionary(), new TempDataDictionary());
     9             var vdcMock = new Mock<IViewDataContainer>();
    10             var helper = new HtmlHelper(viewContext, vdcMock.Object);
    11             string output = helper.UnorderedList(new int[] { 0, 1, 2 });
    12             Assert.AreEqual("<ul><li>0</li><li>1</li><li>2</li></ul>", output);
    13         }

    4-9行都是为实例化HtmlHelper做准备的。

    四、参考

    《Professional ASP.NET MVC 1.0》

    《ProASP.NET MVCFramework》

    http://msdn.microsoft.com/en-us/magazine/dd942838.aspx

    http://www.henrycordes.nl/post/2008/02/MVC-Framework-and-Unit-Test.aspx

    http://srtsolutions.com/blogs/patricksteele/archive/2009/08/23/asp-net-mvc-mvc-contrib-unit-testing.aspx

    http://weblogs.asp.net/leftslipper/archive/2008/04/13/mvc-unit-testing-controller-actions-that-use-tempdata.aspx

    (转自作者:Lance 出处:http://www.cnblogs.com/nuaalfm/ 

  • 相关阅读:
    记录。短信网关.
    TP 笔记~
    FUCK IE FLASH(inline hook)
    API HOOK(MessageBoxA)
    inline hook MessageBox(2)
    c#线程中使用 dataset
    匈牙利算法解决二分图最大匹配
    C#:Array类的排序
    C#:属性
    C#:结构
  • 原文地址:https://www.cnblogs.com/yellowcool/p/7541632.html
Copyright © 2020-2023  润新知