用Moq嘲弄HttpContextBase

我有一个unit testing夹具,我试图在一个ASP.NET MVC控制器上testing一个ControllerAction,这个控制器用于一个Web应用程序的成员函数。 我试图嘲笑testing的HttpContext。 被testing的ControllerAction实际上在HttpContext上设置了属性,例如Session值,Response.Cookies值等等。这不是所有的代码,但是这里是我试图运行的一个粗略的testing样本:

[Test] public void ValidRegistrationDataSuccessfullyCreatesAndRegistersUser() { var context = new Mock<HttpContextBase>() {DefaultValue = DefaultValue.Mock}; context.SetupAllProperties(); var provider = new Mock<MembershipProvider>(new object[] {context.Object}); var controller = new AccountController(context.Object, provider.Object); // This just sets up a local FormCollection object with valid user data // in it to use to attempt the registration InitializeValidFormData(); ActionResult result = controller.Register(_registrationData); Assert.IsInstanceOfType(typeof(ViewResult), result); // Here is where I'd like to attempt to do Assertions against properties // of the HttpContext, like ensuring that a Session object called "User" // exists, and new auth cookie exists on the Response.Cookies collection. // So far I've been unable to successfully check the values of those properties. // I've been unsuccessful in getting those properties setup correctly on my // mock object so that my ControllerAction can actually *set* their values, // and that I can make assertions on them afterwards. The above code actually // generates a StackOverflowException (which I've reported) on the // context.SetupAllProperties() call. What am I doing wrong, or what do I need // to do to be able to set and assert on those context properties? } 

不知道我在做什么错,但我会喜欢它,如果有人可以指出我在正确的方向,并告诉我如何设置这个模拟HttpContextBase对象,使我的控制器可以实际上设置其属性值,我可以断言这些属性,以确保我的ControllerAction正在做我所需要的。

我以错误的方式接近了吗? 我知道MVC控制器有一个ControllerContext,我可以用它来设置Session的值等,但我不知道如何可以嘲笑,而不注入它。 有什么办法呢? (我也需要能够将上下文传递给我的MembershipProvider)这是一个更好的方法吗?

谢谢。

我正在使用他的Pro Asp.NET MVC书籍中包含的一些代码Steve Sanderson的版本…我现在有一个道德两难的问题,不pipe在这里发布代码是否可以。 我如何妥协一个高度精简的版本? ;)

所以这可以很容易地被重用,创build一个类似于下面的类,你将通过你的控制器。 这将设置你的嘲笑,并将其设置为您的控制器的ControllerContext

 public class ContextMocks { public Moq.Mock<HttpContextBase> HttpContext { get; set; } public Moq.Mock<HttpRequestBase> Request { get; set; } public RouteData RouteData { get; set; } public ContextMocks(Controller controller) { //define context objects HttpContext = new Moq.Mock<HttpContextBase>(); HttpContext.Setup(x => x.Request).Returns(Request.Object); //you would setup Response, Session, etc similarly with either mocks or fakes //apply context to controller RequestContext rc = new RequestContext(HttpContext.Object, new RouteData()); controller.ControllerContext = new ControllerContext(rc, controller); } } 

然后在你的testing方法中,你只需要创build一个ContextMocks的实例,并传递你正在testing的控制器对象:

 [Test] Public void test() { var mocks = new ContextMocks(controller); var req = controller.Request; //do some asserts on Request object } 

看起来和克雷格的例子非常相似,但这是Moq v3。 我必须为Steve Sanderson提供道具 – 我将其用作testing各种传统上难以testing的东西的基础:cookies,会话,请求方法,查询string等等。

这是我怎么做的 。

  public static HttpContextBase FakeHttpContext() { var context = new Mock<HttpContextBase>(); var request = new Mock<HttpRequestBase>(); var response = new Mock<HttpResponseBase>(); var session = new Mock<HttpSessionStateBase>(); var server = new Mock<HttpServerUtilityBase>(); var user = new Mock<IPrincipal>(); var identity = new Mock<IIdentity>(); request.Expect(req => req.ApplicationPath).Returns("~/"); request.Expect(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/"); request.Expect(req => req.PathInfo).Returns(string.Empty); response.Expect(res => res.ApplyAppPathModifier(It.IsAny<string>())) .Returns((string virtualPath) => virtualPath); user.Expect(usr => usr.Identity).Returns(identity.Object); identity.ExpectGet(ident => ident.IsAuthenticated).Returns(true); context.Expect(ctx => ctx.Request).Returns(request.Object); context.Expect(ctx => ctx.Response).Returns(response.Object); context.Expect(ctx => ctx.Session).Returns(session.Object); context.Expect(ctx => ctx.Server).Returns(server.Object); context.Expect(ctx => ctx.User).Returns(user.Object); return context.Object; } 

这是由Scott Hanselman发布的MvcMockHelpers库的增强版本。 这是Moq 2.0的代码; 3的语法略有不同。