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

116
[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).
    ...
 }

我的基础控制器有一个覆盖了Initialize方法的实现,它获取了这个requestContext。我正在尝试传递这个requestContext,但是我做错了什么。

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

我在哪里能够获取更多使用Moq进行模拟RequestContext和HttpContext的信息?我正在尝试模拟cookie和通用上下文。

6个回答

70

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

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

这个对我有用,因为它允许我在控制器上设置模拟的HttpContext。 - Joel Malone

43

创建一个请求和响应,然后将它们放到HttpContext中:

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

这个问题是关于基类的,即HttpRequestBase,而不是HttpRequest - 不确定为什么两者都需要,更让人烦恼的是它们都是“密封的”。没有办法设置LogonUserIdentity :( - Chris Kimpton
如果它们被引用马歇尔,仍然可以通过远程访问实现,所以这不应该是一个问题。 - 0100110010101
1
@ChrisKimpton:作为最后的手段,总是可以使用_反射_ ;-) - Oliver
1
当将其附加到控制器时,它会起作用,就像这样: controller.ControllerContext = new ControllerContext( new HttpContextWrapper(httpContextMock), new RouteData(), controller); - Andreas Vendel
可以设置.LogonUserIdentity--_request.Setup(n => n.LogonUserIdentity).Returns((WindowsIdentity.GetCurrent)); - KevinDeus
所有这些都是抽象类,你不能实例化它们。 - Ali Adravi

17

感谢用户 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类型 - 现在有其他的东西吗? - Vincent Buscarello
1
这并不实用,因为HttpRequest中的所有字段都是不可变的。 - A X
我还必须使用这个来修复RouteData https://dev59.com/Y7Xna4cB1Zd3GeqPEQ6N#57005125 - Adel Mourad

7

以下是我如何使用ControllerContext传递一个虚假的应用程序路径:

[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
MVC 代码将执行并抛出空异常(null exception),如果它不存在的话。 - Joshua Ramirez

5
这是一个设置示例:使用Moq模拟HttpContext、HttpRequest和HttpResponse进行单元测试。请注意这些扩展方法,它们真正帮助简化了这些模拟类的使用。
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已重构为

链接已经失效 - 请在您的回答中包含代码。 - Hades

0
var httpResponse = new HttpResponseMessage(HttpStatusCode.OK);
httpResponse.Content = new StringContent("Your response text");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接