Asp.net mvc 用Moq模拟HttpContextBase

Asp.net mvc 用Moq模拟HttpContextBase,asp.net-mvc,moq,Asp.net Mvc,Moq,我有一个单元测试装置,我试图在ASP.NET MVC控制器上测试ControllerAction,该控制器用于web应用程序上的成员资格函数。我试图模拟测试的HttpContext。测试中的ControllerAction实际上在HttpContext上设置属性,例如会话值、响应.Cookies值等。这不是全部代码,但下面是我尝试运行的测试的粗略示例: [Test] public void ValidRegistrationDataSuccessfullyCreatesAndRegistersU

我有一个单元测试装置,我试图在ASP.NET MVC控制器上测试ControllerAction,该控制器用于web应用程序上的成员资格函数。我试图模拟测试的HttpContext。测试中的ControllerAction实际上在HttpContext上设置属性,例如会话值、响应.Cookies值等。这不是全部代码,但下面是我尝试运行的测试的粗略示例:

[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?
}
[测试]
public void validRegistrationDataSuccessfullyCreateandRegistersUser()
{
var context=new Mock(){DefaultValue=DefaultValue.Mock};
SetupAllProperties();
var provider=newmock(新对象[]{context.object});
var控制器=新的AccountController(context.Object、provider.Object);
//这只是使用有效的用户数据设置一个本地FormCollection对象
//在它中,用于尝试注册
初始化EvalidFormData();
ActionResult=controller.Register(注册数据);
IsInstanceOfType(typeof(ViewResult),result);
//这里是我想要尝试对属性进行断言的地方
//HttpContext,比如确保一个名为“User”的会话对象
//存在,并且Response.Cookies集合上存在新的身份验证cookie。
//到目前为止,我无法成功地检查这些属性的值。
//我无法在我的计算机上正确设置这些属性
//模拟对象,以便我的ControllerAction可以实际*设置*它们的值,
//之后我可以对它们进行断言。上面的代码实际上
//在服务器上生成StackOverflowException(我已经报告过)
//SetupAllProperties()调用。我做错了什么,或者我需要什么
//如何设置和断言这些上下文属性?
}
我不确定我做错了什么,但如果有人能给我指出正确的方向,告诉我如何设置这个模拟的HttpContextBase对象,这样我的控制器就可以在其属性上设置值,我就可以对这些属性进行断言,以确保我的ControllerAction正在做我需要它做的事情,我会很高兴

我是不是走错了路?我知道MVC控制器有一个ControllerContext,我可以用它来设置会话等的值,但我不知道如何不注入它就可以模拟类似的东西。有什么方法可以替代吗?(我还需要能够将上下文传递给我的会员资格提供商)这是更好的方法吗

谢谢。

公共静态HttpContextBase FakeHttpContext()
{
var context=newmock();
var request=newmock();
var response=newmock();
var session=newmock();
var server=newmock();
var user=new Mock();
var identity=newmock();
Expect(req=>req.ApplicationPath)。返回(“~/”;
Expect(req=>req.AppRelativeCurrentExecutionFilePath)。返回(“~/”;
Expect(req=>req.PathInfo).Returns(string.Empty);
Expect(res=>res.ApplyAppPathModifier(It.IsAny()))
.返回((字符串virtualPath)=>virtualPath);
Expect(usr=>usr.Identity).Returns(Identity.Object);
identity.ExpectGet(ident=>ident.IsAuthenticated).返回(true);
Expect(ctx=>ctx.Request).Returns(Request.Object);
Expect(ctx=>ctx.Response).Returns(Response.Object);
Expect(ctx=>ctx.Session).Returns(Session.Object);
Expect(ctx=>ctx.Server).Returns(Server.Object);
Expect(ctx=>ctx.User).Returns(User.Object);
返回context.Object;
}

这是的增强版本。这是moq2.0代码;语法在3中略有不同。

我使用的是Steve Sanderson在他的。。。我现在在道德上左右为难,是否可以在这里发布代码。我可以用一个高度精简的版本来折衷一下吗?;)

因此,这可以很容易地被重用,创建一个类似于下面的类,您将通过您的控制器。这将设置模拟并将其设置为控制器的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);
    }
}

看起来与Craig的例子非常相似,但这是MOQv3。为此,我不得不向史蒂夫·桑德森(Steve Sanderson)献计献策——我正以此为基础测试各种传统上难以测试的东西:cookies、会话、请求方法、查询字符串等等

是的,谢谢,但我使用的是Moq 3.1.416.3,所以查看该版本的语法会非常有帮助。主要是因为,很明显,如果我理解正确的话,3.x中的“设置”属性有点不同。感谢您的示例。
request.Expect(req=>req.ApplicationPath)。返回(“~/”
应该是
request.Expect(req=>req.ApplicationPath)。返回(“/”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);
    }
}
[Test]
Public void test()
{
     var mocks = new ContextMocks(controller);
     var req = controller.Request; 
     //do some asserts on Request object
}