`
wangdeshui
  • 浏览: 256976 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

如何进行ASP.NET MVC 的测试

阅读更多

本文参考了http://stephenwalther.com/blog/的内容。

今天需要对ASP.NET MVC的Controller进行测试,我们都知道当我们在测试工程里new一个controller时,这个controller里的httpcontext是空的,也就是session,cookie, form等都是空。

方法一:Mock controller的HttpContext, 暂时失败

那么我们如何对controller进行测试呢,我首先想到的是mock一个httpcontext,这里我用的是Rhino Mocks

public static class MvcMockHelpers

    {

        public static HttpContextBase FakeHttpContext(this MockRepository mocks)

        {

            HttpContextBase context = mocks.PartialMock<HttpContextBase>();

            HttpRequestBase request = mocks.PartialMock<HttpRequestBase>();

            HttpResponseBase response = mocks.PartialMock<HttpResponseBase>();

            HttpSessionStateBase session = mocks.PartialMock<HttpSessionStateBase>();

            HttpServerUtilityBase server = mocks.PartialMock<HttpServerUtilityBase>();

 

            SetupResult.For(context.Request).Return(request);

            SetupResult.For(context.Response).Return(response);               

            SetupResult.For(context.Session).Return(session);

            SetupResult.For(context.Server).Return(server);

 

            mocks.Replay(context);

            return context;

        }

 

        public static HttpContextBase FakeHttpContext(this MockRepository mocks, string url)

        {

            HttpContextBase context = FakeHttpContext(mocks);

            context.Request.SetupRequestUrl(url);

            return context;

        }

 

        public static void SetFakeControllerContext(this MockRepository mocks, Controller controller)

        {

            var httpContext = mocks.FakeHttpContext();

            ControllerContext context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller);

            controller.ControllerContext = context;

        }

下面我们建立一个ASP.NET MVC工程

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Web.Mvc.Ajax;

 

namespace MVCTest.Controllers

{

    [HandleError]

    public class HomeController : Controller

    {

        public ActionResult TestSession()

        {

            Session["name"] = "Jack Wang";

            ViewData["Title"] = "Home Page";

            ViewData["Message"] = "Welcome to ASP.NET MVC!";

            if (Session["CurrentCulture"] != null)

            {

                ViewData["CurrentCulture"] = Session["CurrentCulture"];

            }

            return View();

        }

 

        public ActionResult TestForm()

        {

            ViewData["Name"] = Request.Form["Name"];

            ViewData["Age"] = Request.Form["Age"];

            ViewData["count"] = Request.Form.Count;

            return View();

        }

 

        public ActionResult TestLogin()

        {

            if (User.Identity.IsAuthenticated)

            {

                ViewData["userName"] = User.Identity.Name;

                return View("Admin");

            }

            else

            {

                return RedirectToAction("Index");

            }

        }

 

        public ActionResult Admin()

        {

            if (User.IsInRole("Admin"))

            {

                return View("Admin");

            }

            else

            {

                return RedirectToAction("Index");

            }

        }

 

        public ViewResult Details()

        {

            ViewData["PageSize"] = Request.QueryString["PageSize"];

            ViewData["CurrentPage"] = Request.QueryString["CurrentPage"];

            ViewData["count"] = Request.QueryString.Count;

 

            return View();

        }

        public ViewResult TestCookie()

        {

            ViewData["key"] = Request.Cookies["key"].Value;

            return View();

        }

    }

}

 

测试代码

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Web.Mvc;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using MVCTest;

using MVCTest.Controllers;

using MvcFakes;

using System.Web.SessionState;

using System.Web;

using System.Collections.Specialized;

using Rhino.Mocks;

namespace MVCTest.Tests.Controllers

{

    /// <summary>

    /// Summary description for HomeControllerTestByMock

    /// </summary>

    [TestClass]

    public class HomeControllerTestByMock

    {

        public HomeControllerTestByMock()

        {

            //

            // TODO: Add constructor logic here

            //

        }

        private MockRepository mocks;

        [TestInitialize]

        public void Setup()

        {

            mocks = new MockRepository();

        }

        [TestMethod]

        public void TestSession()

        {

            // Arrange

 

            HomeController controller = new HomeController();

            mocks.SetFakeControllerContext(controller);

            controller.Session.Add("name", "Jack Wang");

            SetupResult.For(controller.Session["CurrentCulture"]).Return("zh-CN");

 

            mocks.ReplayAll();

            // Act

            ViewResult result = controller.TestSession() as ViewResult;

 

            // Assert

            ViewDataDictionary viewData = result.ViewData;

            Assert.AreEqual("Home Page", viewData["Title"]);

            Assert.AreEqual("Welcome to ASP.NET MVC!", viewData["Message"]);

            Assert.AreEqual(controller.Session["name"], "Jack Wang");

            Assert.AreEqual("zh-CN", viewData["CurrentCulture"]);

        }

 

    }

}

运行,测试

image

从错误信息可以看到是因为代码里Session["name"] = "Jack Wang"出错

本人排查很久,只知道mock的controllercontext的Session里没有这个Key,但现在还没有找到如何解决,哪位高人能帮吗解决?

 

二,自己写个模拟的Fake类,测试通过

 

既然这种方法不行,我们只能换一种方法,还好controller的ControllerContext可以赋值,这样我们就通过继承ControllerContext来Fake

using System;

using System.Collections;

using System.Collections.Generic;

using System.Collections.Specialized;

using System.Linq;

using System.Text;

using System.Web;

using System.Web.SessionState;

 

namespace MvcFakes

{

    public class FakeHttpSessionState : HttpSessionStateBase

    {

        private readonly SessionStateItemCollection _sessionItems;

 

        public FakeHttpSessionState(SessionStateItemCollection sessionItems)

        {

            _sessionItems = sessionItems;

        }

 

        public override void Add(string name, object value)

        {

            _sessionItems[name] = value;

        }

 

        public override int Count

        {

            get

            {

                return _sessionItems.Count;

            }

        }

 

        public override IEnumerator GetEnumerator()

        {

            return _sessionItems.GetEnumerator();

        }

 

        public override NameObjectCollectionBase.KeysCollection Keys

        {

            get

            {

                return _sessionItems.Keys;

            }

        }

 

        public override object this[string name]

        {

            get

            {

                return _sessionItems[name];

            }

            set

            {

                _sessionItems[name] = value;

            }

        }

 

        public override object this[int index]

        {

            get

            {

                return _sessionItems[index];

            }

            set

            {

                _sessionItems[index] = value;

            }

        }

 

        public override void Remove(string name)

        {

            _sessionItems.Remove(name);

        }

    }

}

 

using System;

using System.Collections.Specialized;

using System.Web;

 

namespace MvcFakes

{

 

    public class FakeHttpRequest : HttpRequestBase

    {

        private readonly NameValueCollection _formParams;

        private readonly NameValueCollection _queryStringParams;

        private readonly HttpCookieCollection _cookies;

 

        public FakeHttpRequest(NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies)

        {

            _formParams = formParams;

            _queryStringParams = queryStringParams;

            _cookies = cookies;

        }

 

        public override NameValueCollection Form

        {

            get

            {

                return _formParams;

            }

        }

 

        public override NameValueCollection QueryString

        {

            get

            {

                return _queryStringParams;

            }

        }

 

        public override HttpCookieCollection Cookies

        {

            get

            {

                return _cookies;

            }

        }

 

    }

}

 

using System;

using System.Security.Principal;

 

namespace MvcFakes

{

 

 

    public class FakeIdentity : IIdentity

    {

        private readonly string _name;

 

        public FakeIdentity(string userName)

        {

            _name = userName;

 

        }

 

        public string AuthenticationType

        {

            get { throw new System.NotImplementedException(); }

        }

 

        public bool IsAuthenticated

        {

            get { return !String.IsNullOrEmpty(_name); }

        }

 

        public string Name

        {

            get { return _name; }

        }

 

    }

 

 

}

 

using System;

using System.Linq;

using System.Security.Principal;

 

namespace MvcFakes

{

 

    public class FakePrincipal : IPrincipal

    {

        private readonly IIdentity _identity;

        private readonly string[] _roles;

 

        public FakePrincipal(IIdentity identity, string[] roles)

        {

            _identity = identity;

            _roles = roles;

        }

 

        public IIdentity Identity

        {

            get { return _identity; }

        }

 

        public bool IsInRole(string role)

        {

            if (_roles == null)

                return false;

            return _roles.Contains(role);

        }

    }

}

 

using System;

using System.Collections.Specialized;

using System.Security.Principal;

using System.Web;

using System.Web.SessionState;

 

namespace MvcFakes

{

    public class FakeHttpContext : HttpContextBase

    {

        private readonly FakePrincipal _principal;

        private readonly NameValueCollection _formParams;

        private readonly NameValueCollection _queryStringParams;

        private readonly HttpCookieCollection _cookies;

        private readonly SessionStateItemCollection _sessionItems;

 

        public FakeHttpContext(FakePrincipal principal, NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies, SessionStateItemCollection sessionItems )

        {

            _principal = principal;

            _formParams = formParams;

            _queryStringParams = queryStringParams;

            _cookies = cookies;

            _sessionItems = sessionItems;

        }

 

        public override HttpRequestBase Request

        {

            get

            {

                return new FakeHttpRequest(_formParams, _queryStringParams, _cookies);

            }

        }

 

        public override IPrincipal User

        {

            get

            {

                return _principal;

            }

            set

            {

                throw new System.NotImplementedException();

            }

        }

 

        public override HttpSessionStateBase Session

        {

            get

            {

                return new FakeHttpSessionState(_sessionItems);

            }

        }

 

    }

}

 

using System;

using System.Collections.Specialized;

using System.Web;

using System.Web.Mvc;

using System.Web.Routing;

using System.Web.SessionState;

 

namespace MvcFakes

{

 

    public class FakeControllerContext : ControllerContext

    {

        public FakeControllerContext(ControllerBase controller)

            : this(controller, null, null, null, null, null, null)

        {

        }

 

        public FakeControllerContext(ControllerBase controller, HttpCookieCollection cookies)

            : this(controller, null, null, null, null, cookies, null)

        {

        }

 

        public FakeControllerContext(ControllerBase controller, SessionStateItemCollection sessionItems)

            : this(controller, null, null, null, null, null, sessionItems)

        {

        }

 

 

        public FakeControllerContext(ControllerBase controller, NameValueCollection formParams)

            : this(controller, null, null, formParams, null, null, null)

        {

        }

 

 

        public FakeControllerContext(ControllerBase controller, NameValueCollection formParams, NameValueCollection queryStringParams)

            : this(controller, null, null, formParams, queryStringParams, null, null)

        {

        }

 

 

 

        public FakeControllerContext(ControllerBase controller, string userName)

            : this(controller, userName, null, null, null, null, null)

        {

        }

 

 

        public FakeControllerContext(ControllerBase controller, string userName, string[] roles)

            : this(controller, userName, roles, null, null, null, null)

        {

        }

 

 

        public FakeControllerContext

            (

                ControllerBase controller,

                string userName,

                string[] roles,

                NameValueCollection formParams,

                NameValueCollection queryStringParams,

                HttpCookieCollection cookies,

                SessionStateItemCollection sessionItems

            )

            : base(new FakeHttpContext(new FakePrincipal(new FakeIdentity(userName), roles), formParams, queryStringParams, cookies, sessionItems),

            new RouteData(), controller)

        { }

    }

}

 

下面是测试类

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Web.Mvc;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using MVCTest;

using MVCTest.Controllers;

using MvcFakes;

using System.Web.SessionState;

using System.Web;

using System.Collections.Specialized;

namespace MVCTest.Tests.Controllers

{

    /// <summary>

    /// Summary description for HomeControllerTest

    /// </summary>

    [TestClass]

    public class HomeControllerTest

    {

        [TestMethod]

        public void TestSession()

        {

            // Arrange

            HomeController controller = new HomeController();

            var sessionItems = new SessionStateItemCollection();

            sessionItems["CurrentCulture"] = "zh-CN";

            controller.ControllerContext = new FakeControllerContext(controller, sessionItems);

            // Act

            ViewResult result = controller.TestSession() as ViewResult;

 

            // Assert

            ViewDataDictionary viewData = result.ViewData;

            Assert.AreEqual("Home Page", viewData["Title"]);

            Assert.AreEqual("Welcome to ASP.NET MVC!", viewData["Message"]);

            Assert.AreEqual(sessionItems["name"], "Jack Wang");

            Assert.AreEqual("zh-CN", viewData["CurrentCulture"]);

        }

        [TestMethod]

        public void TestFakeFormParams()

        {

 

            var controller = new HomeController();

 

            var formParams = new NameValueCollection { { "Name", "Jack" }, { "Age", "28" } };

            controller.ControllerContext = new FakeControllerContext(controller, formParams);

 

            var result = controller.TestForm() as ViewResult;

            Assert.AreEqual("Jack", result.ViewData["Name"]);

            Assert.AreEqual("28", result.ViewData["Age"]);

            Assert.AreEqual(formParams.Count, result.ViewData["count"]);

        }

 

        [TestMethod]

        public void TestFakeQueryStringParams()

        {

            var controller = new HomeController();

 

            var queryStringParams = new NameValueCollection { { "PageSize", "10" }, { "CurrentPage", "5" } };

            controller.ControllerContext = new FakeControllerContext(controller, null, queryStringParams);

 

            var result = controller.Details() as ViewResult;

            Assert.AreEqual("10", result.ViewData["PageSize"]);

            Assert.AreEqual("5", result.ViewData["CurrentPage"]);

            Assert.AreEqual(queryStringParams.Count, result.ViewData["count"]);

        }

 

        [TestMethod]

        public void TestFakeUser()

        {

            var controller = new HomeController();

 

            controller.ControllerContext = new FakeControllerContext(controller, "Jack Wang");

            var result = controller.TestLogin() as ActionResult;

            Assert.IsInstanceOfType(result, typeof(ViewResult));

            ViewDataDictionary viewData = ((ViewResult)result).ViewData;

            Assert.AreEqual("Jack Wang", viewData["userName"]);

 

 

            controller.ControllerContext = new FakeControllerContext(controller);

            result = controller.TestLogin() as ActionResult;

            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));

        }

 

 

        [TestMethod]

        public void TestFakeUserRoles()

        {

 

            var controller = new HomeController();

 

 

            controller.ControllerContext = new FakeControllerContext(controller, "Jack Wang", new string[] { "Admin" });

            var result = controller.Admin() as ActionResult;

            Assert.IsInstanceOfType(result, typeof(ViewResult));

 

 

            controller.ControllerContext = new FakeControllerContext(controller);

            result = controller.Admin() as ActionResult;

            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));

        }

 

 

 

        [TestMethod]

        public void TestCookies()

        {

 

            var controller = new HomeController();

 

 

            var cookies = new HttpCookieCollection();

            cookies.Add(new HttpCookie("key", "a"));

            controller.ControllerContext = new FakeControllerContext(controller, cookies);

            var result = controller.TestCookie() as ViewResult;

 

 

            Assert.AreEqual("a", result.ViewData["key"]);

        }

    }

}

测试完全通过

image 

 

总结: 个人感觉ASP.NET MVC的测试是很不友好的,和ruby on rails相比,在测试这一块还有很大的距离,希望正式版里这一块能够加强

 

王德水 写于2008-01-05 00:30分

 

本文源码下载

分享到:
评论

相关推荐

    Pro ASP.NET MVC 5 (精通ASP.NET MVC5框架) 中文+英文+配套源代码

    在ASP.NET MVC 5中,这些组件通过接口和依赖注入实现松耦合,增强了代码的可测试性和可维护性。 **ASP.NET MVC 5 的新特性** 1. **身份验证和授权** - ASP.NET MVC 5 引入了新的身份验证系统,基于Owin和Katana...

    asp.net MVC4 CMS

    ASP.NET MVC4 CMS可能使用ASP.NET Identity进行用户认证和授权。这包括注册、登录、密码重置等功能,并且可以集成OAuth、OpenID Connect等外部身份验证服务。 **模块化和插件架构**: 为了保持系统的可扩展性,CMS...

    ASP.NET MVC5

    学习ASP.NET MVC5,开发者可以掌握Web应用程序的高级开发技巧,包括如何组织项目结构、如何处理用户输入、如何进行数据库操作、如何实现用户认证和授权,以及如何调试和测试代码。"J.T.ASP.NET MVC 5.pdf"这个文件很...

    asp.net mvc 示例项目

    - **测试驱动开发(Test-Driven Development, TDD)**:ASP.NET MVC鼓励TDD,可以使用诸如MSTest、NUnit或xUnit等测试框架编写单元测试,确保代码质量。 - ** Areas(区域)**:对于大型项目,ASP.NET MVC提供区域...

    Asp.Net MVC案例教程

    Asp.Net MVC支持单元测试,你可以为控制器、模型和业务逻辑编写测试用例,确保代码质量。这得益于MVC架构的松耦合特性,使得测试变得更加容易。 错误处理和异常过滤器(Exception Filters)是Asp.Net MVC中的重要...

    ASP.NET MVC5 编程实战.pdf

    ASP.NET MVC5 是微软开发的一款用于构建Web应用程序的框架,它结合了模型-视图-控制器(MVC)设计模式、ASP.NET Web Forms组件以及Web API功能,为开发者提供了更灵活、可测试的Web开发解决方案。这本书《ASP.NET ...

    基于ASP.NET MVC项目实例

    ASP.NET MVC(Model-View-Controller)是一种轻量级、基于组件的Web应用程序架构,它由微软开发并应用于.NET Framework中,为开发者提供了构建可测试、灵活且易于维护的Web应用的强大工具。本项目实例是针对初学者...

    ASP.NET MVC 项目集合.zip

    10. **单元测试(Unit Testing)**: ASP.NET MVC项目易于编写单元测试,因为控制器动作方法是无状态的。可以使用 MSTest, NUnit 或 xUnit 等测试框架进行测试。 这个压缩包中的项目文件可能涵盖了以上概念的实际...

    ASP.NET MVC项目源代码设计资料

    6. **测试(Testing)**:由于MVC架构的分层特性,ASP.NET MVC项目易于编写单元测试和集成测试。开发者可以使用如NUnit、Moq或xUnit等测试框架来确保代码质量。 7. **Oxite项目**:在提供的文件列表中,"Oxite"可能...

    ASP.NET MVC4

    10. **测试驱动开发**:ASP.NET MVC4鼓励测试驱动开发,提供了单元测试和集成测试的支持。 学习ASP.NET MVC4,你需要理解MVC模式的基本概念,掌握控制器、视图和模型的创建及交互,同时熟悉使用Razor视图引擎编写...

    AngularJS开发ASP.NET MVC

    ### AngularJS 开发 ASP.NET MVC #### 知识点概览 - **AngularJS与ASP.NET MVC结合的优势** - **AngularJS的特点与优势** - **AngularJS的基本概念(如数据绑定、指令等)** - **如何在ASP.NET MVC项目中引入...

    【全网首发】ASP.NET MVC4开发指南(附带源码)

    ASP.NET MVC4是一种基于Microsoft .NET Framework的开源Web应用程序框架,设计用于构建可维护性和测试性的动态网站。这个"ASP.NET MVC4开发指南"提供了一套全面的学习资源,旨在帮助开发者掌握这一强大的Web开发技术...

    一套通用的Easyui+asp.net mvc开发框架源码

    asp.net MVC5提供了强类型、声明式、测试驱动的开发环境,而Easyui则简化了前端界面的复杂性,实现了前后端的良好分离。 在【压缩包子文件的文件名称列表】"RookeyFrame-v1.0"中,我们可以推测这是框架的初始版本,...

    ASP.NET MVC4 Web编程

    ASP.NET MVC4是一种基于微软.NET Framework的开源web应用程序框架,专为构建可维护性和测试性的动态网站而设计。它结合了MVC(Model-View-Controller)设计模式、ASP.NET的功能性和HTML5的新特性,提供了高效且灵活...

    ASP.NET MVC 5 网站开发之美

    7. **单元测试与TDD**:ASP.NET MVC 5 支持测试驱动开发(TDD),其设计使得应用程序更易于进行单元测试,确保代码质量。 8. **Bootstrap与响应式设计**:很多ASP.NET MVC 5模板集成了Bootstrap框架,提供了一套...

    asp.net MVC4.0安装包和中文包

    ASP.NET MVC4.0是微软开发的一个开源框架,用于构建高度可测试、可维护的Web应用程序。这个框架结合了ASP.NET Web Forms和ASP.NET AJAX的功能,同时引入了Model-View-Controller(MVC)设计模式,使开发者能够更加...

    基于ASP.NET MVC 2 的小程序

    ASP.NET MVC 2 是微软开发的一个用于构建动态网站的开源框架,它基于Model-View-Controller(MVC)设计模式,提供了清晰的架构,有助于分离关注点,提高代码的可测试性和可维护性。本教程将带你深入了解如何利用ASP...

    【免费】ASP.NET MVC5 高级编程[附源码].rar

    ASP.NET MVC5高级编程(第5版.NET开发经典名著)作为Microsoft备受欢迎的MVC技术的最新版本,MVC 5是一个成熟的Web应用程序框架,支持快速的、TDD友好的开发。MVC允许开发人员创建动态的、数据驱动的网站。这样的...

    asp.Net mvc4 实例

    10. **测试**:ASP.NET MVC4支持单元测试和集成测试,可以通过MSTest、NUnit或xUnit等测试框架编写测试用例,确保代码质量。 综上所述,使用VS2010和ASP.NET MVC4,结合SQL2008数据库,我们可以构建出功能强大、...

    ASP.NET MVC开发实战超完整源码

    ASP.NET MVC(Model-View-Controller)是一种基于微软.NET Framework的Web应用程序开发框架,它为构建可维护性和测试性更强的Web应用提供了强大的支持。在本"ASP.NET MVC开发实战超完整源码"中,我们可以深入理解并...

Global site tag (gtag.js) - Google Analytics