Làm cách nào để giả lập HttpContext trong ASP.NET MVC bằng Moq?


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

bộ điều khiển cơ sở của tôi có ghi đè của Khởi tạo lấy là requestContext này. Tôi đang cố gắng vượt qua điều này nhưng tôi đang làm điều gì đó không đúng.

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

Tôi có thể lấy thêm thông tin về cách chế nhạo RequestContext và HttpContext bằng Moq ở đâu? Tôi đang cố gắng chế nhạo cookie và bối cảnh chung.

Câu trả lời:


61

HttpContext là chỉ đọc, nhưng nó thực sự bắt nguồn từ ControllerContext mà bạn có thể đặt.

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

Cái này đã làm việc cho tôi bằng cách cho phép tôi đặt một HttpContext giả trên bộ điều khiển.
Joel Malone

39

Tạo một yêu cầu, phản hồi và đưa cả hai vào HttpContext:

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

Câu hỏi đặt ra là về các lớp * Base, tức là HttpRequestBase, không phải HttpRequest - bản thân tôi không rõ tại sao cả hai đều cần thiết và thậm chí khó chịu hơn là chúng bị "niêm phong". Không có cách nào để đặt LogonUserIdentity :(
Chris Kimpton

Nếu chúng được sắp xếp cho tài liệu tham khảo của tôi, nó vẫn có thể xảy ra thông qua quá trình xóa, vì vậy nó không phải là vấn đề.
0100110010101

1
@ChrisKimpton: Là phương sách cuối cùng, luôn có sự phản ánh ;-)
Oliver

Điều này hoạt động khi gắn nó vào bộ điều khiển, như sau: controller.ControllerContext = new ControllerContext (new HttpContextWrapper (httpContextMock), new RouteData (), controller);
Andreas Vendel

Đúng. bạn thực sự có thể đặt .LogonUserIdentity - _request.Setup (n => n.LogonUserIdentity) .Returns ((WindowsIdentity.GetCurrent));
KevinDeus

12

Cảm ơn người dùng 0100110010101.

Nó hoạt động với tôi và ở đây tôi đã gặp sự cố khi viết testcase cho đoạn mã dưới đây:

 var currentUrl = Request.Url.AbsoluteUri;

Và đây là những dòng đã giải quyết vấn đề

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);

Có thể hữu ích cho những người khác.


Tôi dường như không thể sử dụng loại HttpRequest - bây giờ có phải là thứ khác không?
Vincent Buscarello

1
Điều này không hữu ích vì tất cả các trường trong HttpRequest đều không thay đổi được
A br

6

Đây là ví dụ về cách bạn có thể thiết lập điều này: Mocking HttpContext HttpRequest và HttpResponse cho UnitTests (sử dụng Moq)

Lưu ý các phương thức mở rộng thực sự giúp đơn giản hóa việc sử dụng các lớp giả lập này:

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();

Dưới đây là một ví dụ về cách viết Unit Test bằng moq để kiểm tra xem HttpModule có hoạt động như mong đợi hay không: Unit Test cho HttpModule sử dụng Moq để bọc HttpRequest

Cập nhật: API này đã được cấu trúc lại thành


Liên kết bị hỏng - vui lòng bao gồm mã trong câu trả lời của bạn
Hades

5

Đây là cách tôi sử dụng ControllerContext để chuyển một đường dẫn Ứng dụng giả mạo:

[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
Tại sao bạn cần phải vượt qua một đường dẫn ứng dụng giả mạo?
the_law

Mã MVC sẽ thực thi nó và ném ra một ngoại lệ rỗng nếu nó không có ở đó.
Joshua Ramirez
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.