2008-08-28 43 views
62

Vì vậy, ngữ cảnh bộ điều khiển phụ thuộc vào một số nội bộ asp.net. Một số cách để làm sạch những thử nghiệm đơn vị này là gì? Có vẻ như nó rất dễ dàng để làm tắc nghẽn các bài kiểm tra với tấn thiết lập khi tôi chỉ cần, ví dụ, Request.HttpMethod để trả về "GET".Mocking Asp.net-mvc Điều khiển ngữ cảnh

Tôi đã xem một số ví dụ/người trợ giúp trên mạng nhưng một số đã có ngày. Hình này sẽ là một nơi tốt để giữ mới nhất và lớn nhất.

Tôi đang sử dụng phiên bản mới nhất của tê giác mỉa mai

+0

Tôi đang cân nhắc thực hiện việc này. Nhưng chỉ cần mô phỏng cho kết nối cơ sở dữ liệu. Thay vì kiểm tra ánh xạ cơ sở dữ liệu, tôi đã chuyển hàm này sang một lớp thông thường và chỉ kiểm tra hàm đó mà không có kết nối cơ sở dữ liệu. – MrFox

Trả lời

58

Sử dụng Moq nó trông giống như sau:

var request = new Mock<HttpRequestBase>(); 
request.Expect(r => r.HttpMethod).Returns("GET"); 
var mockHttpContext = new Mock<HttpContextBase>(); 
mockHttpContext.Expect(c => c.Request).Returns(request.Object); 
var controllerContext = new ControllerContext(mockHttpContext.Object 
, new RouteData(), new Mock<ControllerBase>().Object); 

Tôi nghĩ rằng cú pháp Rhino Mocks là tương tự.

+16

Điều này không còn hợp lệ trong MVC3 nữa. Việc truyền vào một RouteData trống sẽ ném ra các ngoại lệ khi phương thức GetRequiredString không ảo, không thể giả được gọi trên RouteData. – ScottKoon

+2

@ScottKoon Vui lòng cung cấp bản trình diễn về hình thức trông giống như – Jon

+1

Câu trả lời cho câu hỏi này cho bạn biết cách giả lập RouteData. http://stackoverflow.com/questions/986183/mocking-the-routedata-class-in-system-web-routing-for-mvc-applications – ScottKoon

1

Tôi thấy rằng quy trình chế nhạo lâu dài là quá nhiều ma sát.

Cách tốt nhất mà chúng tôi đã tìm thấy - sử dụng ASP.NET MVC trên một dự án thực - là trừu tượng hóa HttpContext thành giao diện IWebContext chỉ đơn giản là đi qua. Sau đó, bạn có thể giả lập IWebContext mà không bị đau.

Dưới đây là một example

+1

Bạn có thể giải thích thêm một chút không? – user40097

17

Dưới đây là một đoạn trích từ liên kết của Jason. Nó giống như phương pháp của Phil nhưng sử dụng tê giác.

Lưu ý: mockHttpContext.Request được đặt lại để trả về mockRequest trước nội bộ của mockRequest bị bung ra. Tôi tin rằng thứ tự này là bắt buộc.

// create a fake web context 
var mockHttpContext = MockRepository.GenerateMock<HttpContextBase>(); 
var mockRequest = MockRepository.GenerateMock<HttpRequestBase>(); 
mockHttpContext.Stub(x => x.Request).Return(mockRequest); 

// tell the mock to return "GET" when HttpMethod is called 
mockRequest.Stub(x => x.HttpMethod).Return("GET");    

var controller = new AccountController(); 

// assign the fake context 
var context = new ControllerContext(mockHttpContext, 
        new RouteData(), 
        controller); 
controller.ControllerContext = context; 

// act 
... 
2

tôi đã kết thúc với spec này

public abstract class Specification <C> where C: Controller 
{ 
    protected C controller; 

    HttpContextBase mockHttpContext; 
    HttpRequestBase mockRequest; 

    protected Exception ExceptionThrown { get; private set; } 

    [SetUp] 
    public void Setup() 
    { 
     mockHttpContext = MockRepository.GenerateMock<HttpContextBase>(); 
     mockRequest = MockRepository.GenerateMock<HttpRequestBase>(); 

     mockHttpContext.Stub(x => x.Request).Return(mockRequest); 
     mockRequest.Stub(x => x.HttpMethod).Return("GET"); 


     EstablishContext(); 
     SetHttpContext(); 

     try 
     { 
      When(); 
     } 
     catch (Exception exc) 
     { 
      ExceptionThrown = exc; 
     } 
    } 

    protected void SetHttpContext() 
    { 
     var context = new ControllerContext(mockHttpContext, new RouteData(), controller); 
     controller.ControllerContext = context; 
    } 

    protected T Mock<T>() where T: class 
    { 
     return MockRepository.GenerateMock<T>(); 
    } 

    protected abstract void EstablishContext(); 
    protected abstract void When(); 

    [TearDown] 
    public virtual void TearDown() 
    { 
    } 
} 

và nước trái cây là ở đây

[TestFixture] 
public class When_invoking_ManageUsersControllers_Update :Specification <ManageUsersController> 
{ 
    private IUserRepository userRepository; 
    FormCollection form; 

    ActionResult result; 
    User retUser; 

    protected override void EstablishContext() 
    { 
     userRepository = Mock<IUserRepository>(); 
     controller = new ManageUsersController(userRepository); 

     retUser = new User(); 
     userRepository.Expect(x => x.GetById(5)).Return(retUser); 
     userRepository.Expect(x => x.Update(retUser)); 

     form = new FormCollection(); 
     form["IdUser"] = 5.ToString(); 
     form["Name"] = 5.ToString(); 
     form["Surename"] = 5.ToString(); 
     form["Login"] = 5.ToString(); 
     form["Password"] = 5.ToString(); 
    } 

    protected override void When() 
    { 
     result = controller.Edit(5, form); 
    } 

    [Test] 
    public void is_retrieved_before_update_original_user() 
    { 
     userRepository.AssertWasCalled(x => x.GetById(5)); 
     userRepository.AssertWasCalled(x => x.Update(retUser)); 
    } 
} 

thưởng thức

7

Hoặc bạn có thể làm điều này với Typemock Isolator mà không cần để gửi một bộ điều khiển giả ở tất cả:

Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get"); 
9

Quy trình này dường như đã thay đổi một chút trong MVC2 (tôi đang sử dụng RC1). Giải pháp của Phil Haack không phù hợp với tôi nếu hành động yêu cầu một phương pháp cụ thể ([HttpPost], [HttpGet]). Spelunking xung quanh trong Reflector, có vẻ như phương pháp xác minh các thuộc tính này đã thay đổi. Hiện tại, MVC kiểm tra request.Headers, request.Formrequest.QueryString với giá trị X-HTTP-Method-Override.

Nếu bạn thêm mocks cho các đặc tính này, nó hoạt động:

var request = new Mock<HttpRequestBase>(); 
request.Setup(r => r.HttpMethod).Returns("POST"); 
request.Setup(r => r.Headers).Returns(new NameValueCollection()); 
request.Setup(r => r.Form).Returns(new NameValueCollection()); 
request.Setup(r => r.QueryString).Returns(new NameValueCollection()); 

var mockHttpContext = new Mock<HttpContextBase>(); 
mockHttpContext.Expect(c => c.Request).Returns(request.Object); 
var controllerContext = new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object); 
+1

Điều này làm việc cho tôi, tuy nhiên trong MVC2 RC tôi cũng đã có thêm những điều sau đây: request.Setup (r => r.Files) .Returns (new Mock (). Object); nếu không tôi sẽ nhận được một sự phản đối vô giá trị –

19

Đây là một lớp thử nghiệm đơn vị mẫu sử dụng MSTest và Moq mà chế giễu HttpRequest và HttpResponse đối tượng. (.NET 4.0, ASP.NET MVC 3.0)

Tác vụ điều khiển nhận giá trị từ yêu cầu và đặt tiêu đề http trong đối tượng phản hồi.Các đối tượng ngữ cảnh http khác có thể được mô phỏng theo cách tương tự

[TestClass] 
public class MyControllerTest 
{ 
    protected Mock<HttpContextBase> HttpContextBaseMock; 
    protected Mock<HttpRequestBase> HttpRequestMock; 
    protected Mock<HttpResponseBase> HttpResponseMock; 

    [TestInitialize] 
    public void TestInitialize() 
    { 
     HttpContextBaseMock = new Mock<HttpContextBase>(); 
     HttpRequestMock = new Mock<HttpRequestBase>(); 
     HttpResponseMock = new Mock<HttpResponseBase>(); 
     HttpContextBaseMock.SetupGet(x => x.Request).Returns(HttpRequestMock.Object); 
     HttpContextBaseMock.SetupGet(x => x.Response).Returns(HttpResponseMock.Object); 
    } 

    protected MyController SetupController() 
    { 
     var routes = new RouteCollection(); 
     var controller = new MyController(); 
     controller.ControllerContext = new ControllerContext(HttpContextBaseMock.Object, new RouteData(), controller); 
     controller.Url = new UrlHelper(new RequestContext(HttpContextBaseMock.Object, new RouteData()), routes); 
     return controller; 
    } 

    [TestMethod] 
    public void IndexTest() 
    { 
     HttpRequestMock.Setup(x => x["x"]).Returns("1"); 
     HttpResponseMock.Setup(x => x.AddHeader("name", "value")); 

     var controller = SetupController(); 
     var result = controller.Index(); 
     Assert.AreEqual("1", result.Content); 

     HttpRequestMock.VerifyAll(); 
     HttpResponseMock.VerifyAll(); 
    } 
} 

public class MyController : Controller 
{ 
    public ContentResult Index() 
    { 
     var x = Request["x"]; 
     Response.AddHeader("name", "value"); 
     return Content(x); 
    } 
} 
+0

Rất nhiều người cảm ơn! Nó đã giúp tôi rất nhiều. Tôi ước tôi có thể upvote nó mười lần. –

+0

@Maksym Kozlenko Rất nhiều, cảm ơn rất nhiều. Điều này đã giúp tôi rất nhiều –

Các vấn đề liên quan