2010-10-26 36 views
14

Tôi muốn viết các bài kiểm tra đơn vị cho một dịch vụ web. Tôi tạo dự án thử nghiệm của mình, tham khảo dự án web của tôi (không tham khảo dịch vụ, tham chiếu lắp ráp), sau đó viết một số mã để kiểm tra các dịch vụ web - chúng hoạt động tốt. Tuy nhiên, có một số dịch vụ đảm bảo rằng người dùng đã đăng nhập vào ứng dụng web bằng cách sử dụng HttpContext.Current.User.Identity.IsAuthenticated.Kiểm thử đơn vị dịch vụ web - HttpContext

Trong ngữ cảnh của các thử nghiệm, không có điều gì như HttpContext, vì vậy các kiểm tra luôn thất bại. Các loại dịch vụ web này sẽ được kiểm tra như thế nào?

Trả lời

25

Here là cuộc thảo luận liên quan.

Tôi đã ngừng tham chiếu HttpContext.Current trực tiếp. và sử dụng lớp này để thay thế:

public class HttpContextFactory 
{ 
    private static HttpContextBase m_context; 
    public static HttpContextBase Current 
    { 
     get 
     { 
      if (m_context != null) 
       return m_context; 

      if (HttpContext.Current == null) 
       throw new InvalidOperationException("HttpContext not available"); 

      return new HttpContextWrapper(HttpContext.Current); 
     } 
    } 

    public static void SetCurrentContext(HttpContextBase context) 
    { 
     m_context = context; 
    } 
} 

và sử dụng HttpContextFactory.Current thay vì HttpContext.Current trong mã của chúng tôi.

Sau đó, bạn viết những dòng này trong thử nghiệm của bạn:

 HttpContextFactory.SetCurrentContext(GetMockedHttpContext()); 

nơi GetMockedHttpContext() là từ here và trông như thế này:

private System.Web.HttpContextBase GetMockedHttpContext() 
    { 
     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>(); 

     context.Setup(ctx => ctx.Request).Returns(request.Object); 
     context.Setup(ctx => ctx.Response).Returns(response.Object); 
     context.Setup(ctx => ctx.Session).Returns(session.Object); 
     context.Setup(ctx => ctx.Server).Returns(server.Object); 
     context.Setup(ctx => ctx.User).Returns(user.Object); 
     user.Setup(x => x.Identity).Returns(identity.Object); 
     identity.Setup(id => id.IsAuthenticated).Returns(true); 
     identity.Setup(id => id.Name).Returns("test"); 

     return context.Object; 
    } 

Nó sử dụng một mocking framework gọi moq

Trong của bạn dự án thử nghiệm bạn phải thêm tham chiếu đến System.WebSystem.Web.Abstractions, nơi HttpContextBase được xác định.

+0

Tôi cũng đã bắt đầu thực hiện việc này (thay thế HttpContext bằng HttpContextFactory), và nó thực sự giúp với Kiểm thử Đơn vị (Tôi đã gói các khả năng này trong một API mà bạn có thể xem tại đây http://o2platform.wordpress.com/2011/ 04/05/mocking-httpcontext-httprequest-and-httpresponse-cho-unittests-using-moq /) –

+1

Tôi không sử dụng moq, do đó, điều này đã không làm cho tôi đến 100%, nhưng nó đã được hữu ích. Tôi nhìn vào các vật giả giả của Stephen Walther để được giúp đỡ: http://stephenwalther.com/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context.aspx –

2

Nếu bạn đang sử dụng chế nhạo, bạn có thể quấn logic này trong lớp khác:

interface IAuthenticator 
{ 
    bool IsAuthenticated(); 
} 

và thực hiện thực một:

class Authenticator : IAuthenticator 
{ 
    bool IsAuthenticated() 
    { 
     return HttpContext.Current.User.Identity.IsAuthenticated; 
    } 
} 

nhưng trong các thử nghiệm, tạo ra một mô hình và trở thành sự thật hoặc sai:

Mock<IAuthenticator> mock = new Mock<IAuthenticator>(); 
mock.Expect(x => x.IsAuthenticated()).Returns(true); 
+0

Để hoàn toàn chính xác, tôi nghĩ điều này thực sự là một bài viết và không phải là giả. –

+0

Bạn có nghĩa là chúng ta cần một cuống thay vì giả? Tôi sẽ không đồng ý vì dựa trên xác thực hay không, dịch vụ sẽ hành xử khác nhau do đó chúng tôi cần kỳ vọng để có thể quay trở lại. Tôi không chắc chắn - và không phải là quan tâm - về sự khác biệt của một bài sơ khai và giả nhưng đối với tôi, đó là một giả và không sơ khai. – Aliostad

+0

Nếu ý định là để kiểm tra giao diện IAuthenticator được gọi chính xác thì nó phải là một mô hình. Nếu bạn muốn thử nghiệm một cái gì đó khác nó phải là một sơ khai. Sơ khai sẽ không bao giờ gây ra một bài kiểm tra thất bại. Họ chỉ ở đó để làm cho mọi thứ diễn ra trôi chảy. Dù sao tôi đoán nó phụ thuộc vào khuôn khổ mocking của bạn. Trong Rhino Mocks có sự khác biệt tinh tế giữa mocks và sơ khai: http://stackoverflow.com/questions/463707/what-are-the-differences-between-mocks-and-stubs-on-rhino-mocks –

1

Bạn có thể xem xét việc phụ thuộc vào System.Web.Abstractions.HttpContextBase thay vì u hát HttpContext.Current. Các System.Web.Abstractions lắp ráp có rất nhiều phổ biến ASP.NET Http * lớp học đã được bọc cho bạn. Chúng được sử dụng trên toàn bộ mã ASP.NET MVC. Nếu bạn đang sử dụng một khung công tác IoC/DI, nó khá dễ sử dụng. Ví dụ, trong Ninject:

Bind<HttpContextBase>.ToMethod(x => new HttpContextWrapper(HttpContext.Current)); 

và sau đó trong constructor của bạn ...

public class SomeWebService 
{ 
    private HttpContextBase _httpContext; 

    public SomeWebService(HttpContextBase httpContext) 
    { 
     _httpContext = httpContext; 
    } 

    public void SomeOperationNeedingAuthorization() 
    { 
     IIdentity userIdentity = _httpContext.User.Identity; 

     if (!userIdentity.IsAuthenticated) 
      return; 

     // Do something here... 
    } 
} 

đó là cách đơn giản đi, nhưng tôi hy vọng bạn sẽ có được ý tưởng ... Như Aliostad đề cập, bạn có thể dễ dàng giả HttpContextBase sử dụng Rhino Mocks hoặc Moq, v.v. để kiểm tra SomeOperationNeedingAuthorization.

+0

Bạn cũng có thể xem xét sử dụng một công cụ mocking thương mại, chẳng hạn như Typemock Isolator hoặc JustMock của Telerik, làm giảm bớt việc sử dụng/quản lý các phép trừu tượng Http *. –

0

tôi đã kết thúc việc đưa một tài sản trên các dịch vụ web:

Private mIdentity As System.Security.Principal.IIdentity 
Public Property Identity() As System.Security.Principal.IIdentity 
    Get 
    If mIdentity Is Nothing Then mIdentity = HttpContext.Current.User.Identity 
    Return mIdentity 
    End Get 
    Set(ByVal value As System.Security.Principal.IIdentity) 
    mIdentity = value 
    End Set 
End Property 

Sau đó, trong phương pháp dịch vụ web của tôi:

<WebMethod()> _ 
Public Function GetProject(ByVal projectId As Int32) As String 

    If Me.Identity.IsAuthenticated Then 

    'code here 

    End If 

End Function 

Sau đó, trong thử nghiệm của tôi (Tôi đang sử dụng RhinoMocks):

Dim mockery As New MockRepository() 
Dim mockIdentity As System.Security.Principal.IIdentity = mockery.DynamicMock(Of System.Security.Principal.IIdentity)() 

Dim projectService As New TeamDynamix.Enterprise.Web.Next.ProjectService() 
projectService.Identity = mockIdentity 
mockIdentity.Stub(Function(i As System.Security.Principal.IIdentity) i.IsAuthenticated).Return(True) 
0

Dựa trên các giải pháp trên, tôi đã thực hiện một lớp wrapper trong O2 Platform cho phép người sử dụng dễ dàng của các lớp chế giễu, cho ví dụ này là làm thế nào tôi có thể viết và đọc từ HttpRequest.InputStream

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

xem bài đăng trên blog này để biết thêm chi tiết: http://o2platform.wordpress.com/2011/04/05/mocking-httpcontext-httprequest-and-httpresponse-for-unittests-using-moq/

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