Unit Testing Web Services - HttpContext

后端 未结 5 831
日久生厌
日久生厌 2021-01-31 00:20

I want to write unit tests for a web service. I create my test project, reference my web project (not service reference, assembly reference), then write some code to test the we

相关标签:
5条回答
  • 2021-01-31 00:40

    You might consider taking a dependency on System.Web.Abstractions.HttpContextBase instead of using HttpContext.Current. The System.Web.Abstractions assembly has a lot of common ASP.NET Http* classes already wrapped for you. They're used all over the ASP.NET MVC code. If you're using an IoC/DI framework, it's pretty easy to use. For example, in Ninject:

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

    and then in your constructor...

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

    That's WAY oversimplified, but I hope you get the idea... As Aliostad mentioned, you can easily mock HttpContextBase using Rhino Mocks or Moq, etc. to test SomeOperationNeedingAuthorization.

    0 讨论(0)
  • 2021-01-31 00:51

    I ended up putting a property on the web service:

    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
    

    Then in my web service method:

    <WebMethod()> _
    Public Function GetProject(ByVal projectId As Int32) As String
    
      If Me.Identity.IsAuthenticated Then
    
        'code here
    
      End If
    
    End Function
    

    Then in my test (I'm using 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 讨论(0)
  • 2021-01-31 00:55

    If you are using mocking, you can wrap this logic in another class:

    interface IAuthenticator
    {
       bool IsAuthenticated();
    }
    

    and implement the real one:

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

    but in the test, create a mock and return true or false:

    Mock<IAuthenticator> mock = new Mock<IAuthenticator>();
    mock.Expect(x => x.IsAuthenticated()).Returns(true);
    
    0 讨论(0)
  • 2021-01-31 00:58

    Here is a related discussion.

    I stopped referencing HttpContext.Current directly. and use this class instead:

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

    and use HttpContextFactory.Current instead of HttpContext.Current in our code.

    Then you write this in your test:

            HttpContextFactory.SetCurrentContext(GetMockedHttpContext());
    

    where GetMockedHttpContext() is from here and looks like this:

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

    It uses a mocking framework called moq

    In your test project you have to add a reference to System.Web and System.Web.Abstractions, where HttpContextBase is defined.

    0 讨论(0)
  • 2021-01-31 01:02

    Based on the solution above, I've implemented a wrapper class in the O2 Platform that allows the easy use of these mocking classes, for example this is how I can write and read from the 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();
    

    see this blog post for more details: http://o2platform.wordpress.com/2011/04/05/mocking-httpcontext-httprequest-and-httpresponse-for-unittests-using-moq/

    0 讨论(0)
提交回复
热议问题