ฉันจะจำลอง HttpContext ใน ASP.NET MVC โดยใช้ 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).
    ...
 }

ตัวควบคุมฐานของฉันมีการแทนที่การเริ่มต้นที่ได้รับเป็น requestContext นี้ ฉันพยายามจะผ่านเรื่องนี้ไป แต่ฉันทำอะไรไม่ถูก

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

ฉันจะหาข้อมูลเพิ่มเติมเกี่ยวกับการจำลอง RequestContext และ HttpContext โดยใช้ Moq ได้ที่ไหน ฉันพยายามล้อเลียนคุกกี้และบริบททั่วไป

คำตอบ:


61

HttpContext เป็นแบบอ่านอย่างเดียว แต่จริงๆแล้วได้มาจาก ControllerContext ซึ่งคุณสามารถตั้งค่าได้

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

อันนี้ใช้ได้ผลสำหรับฉันโดยให้ฉันตั้งค่า HttpContext จำลองบนคอนโทรลเลอร์
Joel Malone

39

สร้างคำขอตอบกลับและนำทั้งสองไปยัง 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

ใช้งานได้เมื่อเชื่อมต่อกับคอนโทรลเลอร์เช่นนี้: controller.ControllerContext = new ControllerContext (ใหม่ HttpContextWrapper (httpContextMock), RouteData () ใหม่, คอนโทรลเลอร์);
Andreas Vendel

ใช่. แน่นอนคุณสามารถตั้งค่า. LogonUserIdentity - _request.Setup (n => n.LogonUserIdentity) .Returns ((WindowsIdentity.GetCurrent));
KevinDeus

12

ขอบคุณผู้ใช้ 0100110010101

มันใช้ได้ผลสำหรับฉันและที่นี่ฉันมีปัญหาขณะเขียน testcase สำหรับรหัสด้านล่าง:

 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 br

5

นี่คือวิธีที่ฉันใช้ 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 จะดำเนินการและโยนข้อยกเว้นที่เป็นโมฆะหากไม่มี
Joshua Ramirez

5

นี่คือตัวอย่างวิธีการตั้งค่านี้: Mocking 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();

นี่คือตัวอย่างวิธีการเขียน Unit Test โดยใช้ moq เพื่อตรวจสอบว่า HttpModule ทำงานตามที่คาดไว้: Unit Test for HttpModule โดยใช้ Moq เพื่อตัด HttpRequest

อัปเดต: API นี้ได้รับการปรับโครงสร้างใหม่เป็น


ลิงก์เสียโปรดใส่รหัสในคำตอบของคุณ
Hades
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.