2009-08-04 36 views
21

Tôi có một vật cố đơn vị kiểm tra, trong đó tôi đang cố gắng để thử nghiệm một ControllerAction trên một bộ điều khiển ASP.NET MVC mà được sử dụng cho các chức năng thành viên trên một ứng dụng web. Tôi đang cố gắng để thử HttpContext cho các bài kiểm tra. ControllerAction trong thử nghiệm thực sự đặt các thuộc tính trên HttpContext, chẳng hạn như các giá trị Session, các giá trị Response.Cookies, vv. Đây không phải là tất cả các mã, nhưng đây là một mẫu thô của thử nghiệm mà tôi đang cố gắng chạy :Mocking HttpContextBase với Moq

[Test] 
public void ValidRegistrationDataSuccessfullyCreatesAndRegistersUser() 
{ 
    var context = new Mock<HttpContextBase>() {DefaultValue = DefaultValue.Mock}; 
    context.SetupAllProperties(); 
    var provider = new Mock<MembershipProvider>(new object[] {context.Object}); 
    var controller = new AccountController(context.Object, provider.Object); 
    // This just sets up a local FormCollection object with valid user data 
    // in it to use to attempt the registration 
    InitializeValidFormData(); 
    ActionResult result = controller.Register(_registrationData); 
    Assert.IsInstanceOfType(typeof(ViewResult), result); 
    // Here is where I'd like to attempt to do Assertions against properties 
    // of the HttpContext, like ensuring that a Session object called "User" 
    // exists, and new auth cookie exists on the Response.Cookies collection. 
    // So far I've been unable to successfully check the values of those properties. 
    // I've been unsuccessful in getting those properties setup correctly on my 
    // mock object so that my ControllerAction can actually *set* their values, 
    // and that I can make assertions on them afterwards. The above code actually 
    // generates a StackOverflowException (which I've reported) on the 
    // context.SetupAllProperties() call. What am I doing wrong, or what do I need 
    // to do to be able to set and assert on those context properties? 
} 

Không chắc gì tôi đang làm sai, nhưng tôi rất muốn nó nếu ai đó có thể chỉ cho tôi đi đúng hướng và chỉ cho tôi làm thế nào để thiết lập đối tượng HttpContextBase giả này như vậy mà điều khiển của tôi thực sự có thể thiết lập các giá trị về các thuộc tính của nó và tôi có thể xác nhận các thuộc tính đó để đảm bảo rằng ControllerAction của tôi đang làm những gì tôi cần.

Tôi có đang tiếp cận cách này sai không? Tôi biết rằng bộ điều khiển MVC có một ControllerContext mà tôi có thể sử dụng để thiết lập các giá trị cho Session, vv, nhưng tôi không thể tìm ra cách mà một cái gì đó như thế có thể được chế nhạo mà không cần tiêm nó. Có cách nào để làm điều đó thay thế không? (Tôi cũng cần để có thể vượt qua bối cảnh trong thành viên của tôi MembershipProvider quá) Đó có phải là một cách tiếp cận tốt hơn?

Cảm ơn.

Trả lời

31

Tôi đang sử dụng phiên bản của một số mã mà Steve Sanderson đưa vào trong số Pro Asp.NET MVC book của mình ... và tôi hiện đang gặp khó khăn về mặt đạo đức cho dù có được đăng mã ở đây hay không. Làm thế nào về tôi thỏa hiệp với một phiên bản cao tước xuống? ;)

Vì vậy, đây có thể dễ dàng được tái sử dụng, tạo ra một lớp tương tự như dưới đây mà bạn sẽ vượt qua điều khiển của bạn. Điều này sẽ thiết lập mocks của bạn và đặt chúng vào của bộ điều khiển của bạn ControllerContext

public class ContextMocks 
{ 
    public Moq.Mock<HttpContextBase> HttpContext { get; set; } 
    public Moq.Mock<HttpRequestBase> Request { get; set; } 
    public RouteData RouteData { get; set; } 

    public ContextMocks(Controller controller) 
    { 
     //define context objects 
     HttpContext = new Moq.Mock<HttpContextBase>(); 
     HttpContext.Setup(x => x.Request).Returns(Request.Object); 
     //you would setup Response, Session, etc similarly with either mocks or fakes 

     //apply context to controller 
     RequestContext rc = new RequestContext(HttpContext.Object, new RouteData()); 
     controller.ControllerContext = new ControllerContext(rc, controller); 
    } 
} 

Và sau đó trong phương pháp thử nghiệm của bạn, bạn muốn chỉ cần tạo một thể hiện của ContextMocks và vượt qua trong các đối tượng điều khiển bạn đang thử nghiệm:

[Test] 
Public void test() 
{ 
    var mocks = new ContextMocks(controller); 
    var req = controller.Request; 
    //do some asserts on Request object 
} 

Có vẻ rất giống với ví dụ của Craig, nhưng điều này là với Moq v3. Tôi phải cung cấp đạo cụ cho Steve Sanderson cho việc này - Tôi đang sử dụng điều này làm cơ sở để thử nghiệm tất cả các loại nội dung khó kiểm tra theo truyền thống: cookie, phiên, phương thức yêu cầu, truy vấn và hơn thế nữa!

+0

Tôi có anh cuốn sách, nhưng chỉ có nó một vài ngày trước, vì vậy tôi đoán tôi đã không nhận được để phần đó được nêu ra. Nếu bạn có thể đưa tôi đến phần trong cuốn sách đó, nơi bạn lấy mã mẫu từ đó, điều đó thật tuyệt vời. Cảm ơn rất nhiều. –

+0

Kiểm tra kết thúc của ch.9. Tôi không có nó trước mặt tôi, nhưng điều đó có vẻ là nó liếc nhìn vào bảng nội dung của cuốn sách trên amazon. –

+0

Tìm thấy nó. Đó là * chính xác * những gì tôi cần. Giờ thì tất cả đều hoạt động. Cám ơn rất nhiều. –

22

Here's how I do it.

public static HttpContextBase FakeHttpContext() 
    { 
     var context = new Mock<HttpContextBase>(); 
     var request = new Mock<HttpRequestBase>(); 
     var response = new Mock<HttpResponseBase>(); 
     var session = new Mock<HttpSessionStateBase>(); 
     var server = new Mock<HttpServerUtilityBase>(); 
     var user = new Mock<IPrincipal>(); 
     var identity = new Mock<IIdentity>(); 

     request.Expect(req => req.ApplicationPath).Returns("~/"); 
     request.Expect(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/"); 
     request.Expect(req => req.PathInfo).Returns(string.Empty); 
     response.Expect(res => res.ApplyAppPathModifier(It.IsAny<string>())) 
      .Returns((string virtualPath) => virtualPath); 
     user.Expect(usr => usr.Identity).Returns(identity.Object); 
     identity.ExpectGet(ident => ident.IsAuthenticated).Returns(true); 

     context.Expect(ctx => ctx.Request).Returns(request.Object); 
     context.Expect(ctx => ctx.Response).Returns(response.Object); 
     context.Expect(ctx => ctx.Session).Returns(session.Object); 
     context.Expect(ctx => ctx.Server).Returns(server.Object); 
     context.Expect(ctx => ctx.User).Returns(user.Object); 

     return context.Object; 
    } 

Đây là phiên bản nâng cao của the MvcMockHelpers library released by Scott Hanselman. Đây là mã Moq 2.0; cú pháp hơi khác trong 3.

+0

Vâng, cảm ơn, nhưng tôi đang sử dụng Moq 3.1.416.3, vì vậy sẽ rất hữu ích khi xem cú pháp cho phiên bản đó. Chủ yếu là vì, rõ ràng, "thiết lập" tài sản là khá một chút khác nhau trong 3.x nếu tôi hiểu chính xác. Cảm ơn ví dụ mặc dù. –

+6

Thay thế Expect with Setup và nó sẽ hoạt động như hiện trạng. –

+0

'request.Expect (req => req.ApplicationPath) .Returns ("~ /"); 'nên được' request.Expect (req => req.ApplicationPath) .Returns ("/"); ' –

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