- 浏览: 246973 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (293)
- web (1)
- [随笔分类]项目管理 (30)
- [随笔分类]WCF (14)
- 未分类 (1)
- [随笔分类]Linq (4)
- [随笔分类]C#基础 (24)
- 项目 (1)
- [网站分类]3.非技术区(技术之外的文章,但不要涉及任何政治内容) (8)
- [网站分类]1.首页原创精华.NET区(包含架构设计、设计模式)(对首页文章的要求:原创、高质量、经过认真思考并精心写作) (9)
- [随笔分类]Ubuntu (4)
- ASP.Net (1)
- [网站分类]2..NET新手区(用于发表不合适发表在首页的.NET技术文章,包括小经验、小技巧) (30)
- [随笔分类]ASP.NET MVC (20)
- [随笔分类]ASP.NET (3)
- [随笔分类]程序员厨房 (4)
- [随笔分类]英语学习 (28)
- [网站分类]4.其他技术区 (1)
- [随笔分类]Silverlight (12)
- [随笔分类]CodeSmith (8)
- [随笔分类]其他 (4)
- [随笔分类]Ruby (4)
- [发布至博客园首页] (34)
- [网站分类]其他技术区 (3)
- [随笔分类]Ruby on Rails (2)
- [网站分类].NET新手区 (33)
- [随笔分类]TDD (1)
- [随笔分类]不谈技术 (2)
- [网站分类]非技术区 (7)
最新评论
-
yicone:
You make a mistake when paste t ...
WCF步步为营(一):简单示例 -
jinweijie:
你好,这个实现不错,但是在用了scriptmanager以后就 ...
在服务器端保存ViewState
本文参考了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"]);
}
}
}
运行,测试
从错误信息可以看到是因为代码里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"]);
}
}
}
测试完全通过
总结: 个人感觉ASP.NET MVC的测试是很不友好的,和ruby on rails相比,在测试这一块还有很大的距离,希望正式版里这一块能够加强
王德水 写于2008-01-05 00:30分
发表评论
-
ASP.NET MVC源码现在可以下载了(翻译)
2008-03-22 09:44 902上个月我在blog里介绍了ASP.NET MVC Roadm ... -
ASP.NET MVC+LINQ开发一个图书销售站点
2008-03-29 17:12 1296园子里已经有很多人讲解了其理论知识,网上也有不少示例,但是很多 ... -
Linq to SQL Dynamic 动态查询
2008-04-01 15:09 1017在开发中我们常需要使用动态的条件来组合查询,scotte博客里 ... -
使用ASP.NET 3.5 Extensions管理浏览器历史:使用服务器端
2008-04-08 13:15 594我们知道当我们使用ASP.NET AJAX的一些方便的服务端控 ... -
客户比产品更重要
2008-04-12 15:49 605发现博客园里99%都是技术文章,很少有管理的经验分享 ... -
WPF 全球化和本地化(图解)
2008-04-12 16:15 795当您将自己的产品限制为只能通过一种语言使用时,您便将潜在的客户 ... -
项目经理如何参与任务管理
2008-04-14 17:55 649每个项目经理可能都会 ... -
.NET环境下每日集成
2008-04-24 17:36 1352本系列主要介绍了.Net环境下如何使用CruiseContro ... -
项目经理虚拟管理客户
2008-05-28 11:26 530项目经理做项目时经常 ... -
从中国男足看项目管理
2008-06-16 11:39 404国足1:2 不敌伊拉克后,彻底无缘本届世界杯,我想比赛时和赛后 ... -
敏捷的 "道"
2008-11-19 14:10 479本文摘要 敏捷的路上 ... -
在服务器端保存ViewState
2008-11-20 16:51 5501.比较 Asp.net 的一个强大的功能就是ViewStat ... -
TDD实验2:使用VSTS 的单元测试功能
2008-12-10 08:25 768我们要实现的功能是,发工资时自动向我们发送邮件,如果工资少于1 ... -
TDD Tip:方法内部New出来的对象如何Mock
2008-12-16 00:27 1156解决的问题:方法内部new的对象在测试时希望能够用mock对象 ... -
Web测试:Selenium使用
2008-12-23 10:49 1587<style> .confluenceTable ... -
谈软件协作:君子和而不同,小人同而不和
2008-12-31 18:39 670我们知道现在的软件开 ... -
如何使ASP.NET MVC Controller易测试呢?
2009-01-05 23:25 945昨天那篇文章如何进行ASP.NET MVC 的测试,虽然通过自 ... -
ASP.NET MVC AJAX的调用
2009-01-10 08:21 3728在ASP.NET MVC beta中我们可以使用Ajax.Be ... -
IIS7 配置ASP.NET 2.0, WCF, ASP.NET MVC
2009-01-16 17:50 4579ASP.NET 2.0 部署 1.首先打开win7 的特性,路 ... -
一步一步学Ruby(一): Ruby介绍
2009-01-21 00:16 757文章摘要 Ruby是如何来的 准备 ...
相关推荐
ASP.NET MVC5高级编程(第5版.NET开发经典名著)作为Microsoft备受欢迎的MVC技术的最新版本,MVC 5是一个成熟的Web应用程序框架,支持快速的、TDD友好的开发。MVC允许开发人员创建动态的、数据驱动的网站。这样的...
ASP.NET MVC 是微软官方提出的一种Web开发框架,通过M是模型(model)-V视图(view)-C控制器(controller)l来设计创建Web应用程序。截至目前最新版本是MVC5,相对于之前的版本MVC5其可扩展性、易用性等方面都不很大的...
介绍了这个框架的方方面面,贯穿《ASP.NET MVC实战》始终的是MVC框架的特性及其重要的设计理念(关注点分离、依赖注入等),一个完整的开发过程(包括建立模型、编码和测试)为开发人员提供了熟悉这一新框架的极好示范,...
第11章:并行计算、异步和实时数据操作 第12章:缓存 第13章:客户端优化技术 第14章:高级路由 第15章:可复用UI组件 第16章:日志 第17章:自动测试 第18章:自动化生成 第19章:部署 附录A ASP.NET MVC与Web Form...
它提供了高生产率的编程模型,结合ASP.NET的全部优势,使代码架构更整洁,可进行测试驱动开发,并使程序有强大的可扩展性。 通过本书你将学到: 获得对ASP.NET MVC 5体系构架的完整理解 了解第ASP.NET MVC 5的新特性...
模型-视图-控制器 (MVC) 体系结构...可测试性非常高的轻型演示框架,(与基于 Web 窗体的应用程序一样)它集成了现有的 ASP.NET 功能,如 母版页和基于成员资格的身份验证。MVC 框架在 System.Web.Mvc 程序集中定义。
ASP.NET MVC5高级编程(第5版.NET开发经典名著)作为Microsoft备受欢迎的MVC技术的最新版本,MVC 5是一个成熟的Web应用程序框架,支持快速的、TDD友好的开发。MVC允许开发人员创建动态的、数据驱动的网站。这样的...
ASP.NET MVC架构是以一些核心原则(可扩展性、可测试性和关注点分离)为指导从头设计而成的。该架构添加了各种约定以帮助开发人员走向成功,并且提供了适合于Web工作方式的流线型开发体验。 对于想剥离抽象层并接近...
开发实践篇通过一套完整的留言板系统案例详述ASP.NET MVC 2的开发技巧与流程,以及ASP.NET MVC的安装部署和单元测试方法。 《ASP.NET MVC2开发实战》适合对MVC架构感兴趣的ASP.NET开发人员阅读。
MVC专家“梦之队”对ASP.NET MVC 4的全新诠释 由Microsoft专家和极受敬重的软件开发社区负责人撰写的《ASP.NET MVC 4高级编程(第4版)》将带您学习最前沿的Web框架:ASP.NET MVC 4。本书开篇简要介绍ASP.NET MVC框架...
解释ASP.NET MVC框架与“文件页”Web框架的不同之处 ◆ 介绍控制器、视图、模型、表单、HTML辅助方法、数据注解、验证、成员资格、授权、安全和路由 ◆ 着重介绍最核心的主题:Ajax、jQuery、NuGet、依赖注入、单元...
它提供了高生产率的编程模型,结合ASP.NET的全部优势,促成更整洁的代码架构、测试驱动开发和强大的可扩展性。 本书涵盖ASP.NET MVC 5的所有开发优势技术,包括用C#属性定义路由技术及重写过滤器技术等。且构建MVC...
ASP.NET MVC 4高级编程(第4版)中文版 高清扫描,学习ASP.NET MVC4圣典之作,一册在手,拨云见日。(因超出本人可上传大小限制,只好分卷上传,请同时下载part1和part2后再解压)。本书简明易懂,用趣味的引导方式...
《ASP.NET MVC 3 高级编程》主要内容是描述视图的概念,探讨Razor语法、NuGet、单元测试等,解释控制器在MVC框架中的作用,以及模型在绑定和数据访问策略中发挥的作用,演示如何显示和处理表单,涵盖添加到April ...
ASP.NET MVC 是微软创建用于替代ASP.NET Web Forms应用的一种新的Web开发框架 测试驱动开发是一种开发方法,是开发人员参与的活动。 其效果是以可执行的形式文档化你的需求,迫使你分清职责隔离依赖以驱动你的设计,...
asp.net mvc+Bootstrap Fileinput框架实现的文件上传,实例经过测试请放心下载参考。
12.3 单元测试用于asp.net mvc应用程序的技巧和窍门 291 12.3.1 控制器测试 291 12.3.2 路由测试 296 12.3.3 验证测试 298 12.4 小结 302 第13章 扩展asp.net mvc 303 13.1 模型扩展 304 13.1.1 把请求数据...
ASP.NET MVC 框架是一个可测试性非常高的轻型演示框架,(与基于 Web 窗体的应用程序一样)它集成了现有的 ASP.NET 功能,如母版页和基于成员资格的身份验证。 MVC 框架在 System.Web.Mvc 程序集中定义
第1章 MVC概述 第2章 与数据的对话:Model与ADO.NET 第3章 LINQ:驱动数据的查询功能 第4章 EF 第5章 路由(Routing) 第6章 控制器(Controller) ...附录A ASP.NET MVC 5.1与ASP.NET MVC 5.2 附录B ASP.NET MVC 6
除了ASP.NET MVC框架本身,作者还介绍了Onion Architecture、领域驱动设计(DDD)、测试驱动开发(TDD)、控制反转(IoC)以及其它一些真实项目中经常用到的类库(和技术)。 本书章节如下: ASP.NET MVC框架入门 ...