如何使用Moq在ASP.NET MVC中模拟HttpContext?


101
[TestMethod]
public void Home_Message_Display_Unknown_User_when_coockie_does_not_exist()
{
    var context = new Mock<HttpContextBase>();
    var request = new Mock<HttpRequestBase>();
    context
        .Setup(c => c.Request)
        .Returns(request.Object);
    HomeController controller = new HomeController();

    controller.HttpContext = context; //Here I am getting an error (read only).
    ...
 }

我的基本控制器重写了初始化此请求上下文的初始化。我正在努力做到这一点,但我做的事情不正确。

protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
    base.Initialize(requestContext);
}

在哪里可以获取有关使用Moq模拟我的RequestContext和HttpContext的更多信息?我正在尝试模拟cookie和一般上下文。

Answers:


61

HttpContext是只读的,但实际上是从ControllerContext派生的,您可以设置它。

 controller.ControllerContext = new ControllerContext( context.Object, new RouteData(), controller );

通过允许我在控制器上设置模拟HttpContext,这为我工作。
乔尔·马龙

39

创建一个请求,响应并将它们都放到HttpContext中:

HttpRequest httpRequest = new HttpRequest("", "http://mySomething/", "");
StringWriter stringWriter = new StringWriter();
HttpResponse httpResponse = new HttpResponse(stringWriter);
HttpContext httpContextMock = new HttpContext(httpRequest, httpResponse);

问题是关于* Base类,即HttpRequestBase而不是HttpRequest-不知道为什么我自己需要这两个类,甚至不确定它们被“密封”了。无法设置LogonUserIdentity :(
克里斯·金普顿

如果他们被编组为我的参考资料,则仍然可以通过远程处理来实现,因此这不是问题。
0100110010101

1
@ChrisKimpton:作为最后的手段,总会有反思 ;-)
Oliver

当将它附加到控制器时,这是可行的,如下所示:controller.ControllerContext = new ControllerContext(new HttpContextWrapper(httpContextMock),new RouteData(),controller);
Andreas Vendel 2014年

是。您确实可以设置.LogonUserIdentity-_request.Setup(n => n.LogonUserIdentity).Returns((WindowsIdentity.GetCurrent));
KevinDeus 2014年

12

感谢用户0100110010101。

它对我有用,在编写下面的代码测试用例时,我遇到了一个问题:

 var currentUrl = Request.Url.AbsoluteUri;

这是解决问题的路线

HomeController controller = new HomeController();
//Mock Request.Url.AbsoluteUri 
HttpRequest httpRequest = new HttpRequest("", "http://mySomething", "");
StringWriter stringWriter = new StringWriter();
HttpResponse httpResponse = new HttpResponse(stringWriter);
HttpContext httpContextMock = new HttpContext(httpRequest, httpResponse);
controller.ControllerContext = new ControllerContext(new HttpContextWrapper(httpContextMock), new RouteData(), controller);

可能会对其他人有所帮助。


我似乎无法使用HttpRequest类型-现在还有其他吗?
文森特·布斯卡洛

1
这是没有用的,因为在HttpRequest的所有字段是不可变的
的BR

6

这是一个设置示例:模拟HttpContext HttpRequest和HttpResponse进行UnitTests(使用Moq)

注意扩展方法,这些方法实际上有助于简化此模拟类的用法:

var mockHttpContext = new API_Moq_HttpContext();

var httpContext = mockHttpContext.httpContext();

httpContext.request_Write("<html><body>".line()); 
httpContext.request_Write("   this is a web page".line());  
httpContext.request_Write("</body></html>"); 

return httpContext.request_Read();

这是一个如何使用moq编写单元测试以检查HttpModule是否按预期工作的示例:使用Moq封装HttpRequest的HttpModule单元测试

更新:此API已重构为


链接被打破-请在你的答案代码
阎王

5

这是我使用ControllerContext传递伪造的Application路径的方法:

[TestClass]
public class ClassTest
{
    private Mock<ControllerContext> mockControllerContext;
    private HomeController sut;

    [TestInitialize]
    public void TestInitialize()
    {
        mockControllerContext = new Mock<ControllerContext>();
        sut = new HomeController();
    }
    [TestCleanup]
    public void TestCleanup()
    {
        sut.Dispose();
        mockControllerContext = null;
    }
    [TestMethod]
    public void Index_Should_Return_Default_View()
    {

        // Expectations
        mockControllerContext.SetupGet(x => x.HttpContext.Request.ApplicationPath)
            .Returns("/foo.com");
        sut.ControllerContext = mockControllerContext.Object;

        // Act
        var failure = sut.Index();

        // Assert
        Assert.IsInstanceOfType(failure, typeof(ViewResult), "Index() did not return expected ViewResult.");
    }
}

1
为什么需要通过伪造的应用程序路径?
the_law 2011年

MVC代码将执行它,如果不存在则抛出null异常。
2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.