views:

35

answers:

1

This post relates to two other posts, here and here.

I'm new to Unit Testing & Mocking. I have a test fixture that is trying to mock a HttpContext object including the response and request. I think the test code is not setup properly, as after calling the handler I get an error immediately. There error I am getting is:

UnitTests.UADHandlerFixture.Request_Is_Object: System.NullReferenceException : Object reference not set to an instance of an object.

at Abstract.BaseHttpHandler.get_Request() in BaseHttpHandler.cs:line 21

at Abstract.BaseHttpHandler.get_IsRequestFromUAD() in BaseHttpHandler.cs:line 23

at Handlers.UADTimeHttpHandler.ProcessRequest(HttpContextBase context) in UADTimeHttpHandler.cs:line 19

at UnitTests.UADHandlerFixture.Request_Is_Object() in UADHttpHanderTests.cs:line 47

The test code is this:

    [TestFixture]
public class UADHandlerFixture
{
    private Mock<HttpContextBase> _mockHttpContext;
    private Mock<HttpRequestBase> _mockHttpRequest;
    private Mock<HttpResponseBase> _mockHttpResponse;
    private UADTimeHttpHandler _handler;
    private WindsorContainer _container;

    [SetUp]
    public void Init()
    {
        _mockHttpRequest = new Mock<HttpRequestBase>();
        _mockHttpResponse = new Mock<HttpResponseBase>();
        _mockHttpContext = new Mock<HttpContextBase>();
        _container = new WindsorContainer();
        _container.AddComponent<ILogger, FakeLogger>();
        _container.AddComponent<IDataRepository, FakeDataRepository>();

        _mockHttpContext.SetupGet(x => x.Application[0]).Returns(_container);
        _mockHttpContext.SetupGet(x => x.Request).Returns(_mockHttpRequest.Object);
        _mockHttpContext.SetupGet(x => x.Response).Returns(_mockHttpResponse.Object);

        _handler = new UADTimeHttpHandler();
    }

    [Test]
    public void Request_Is_Object()
    {
        _handler.ProcessRequest(_mockHttpContext.Object);
    }
}

Handler:

    public class UADTimeHttpHandler : BaseHttpHandler
{
    public override void ProcessRequest(HttpContextBase context)
    {
        if (IsRequestFromUAD)
        {
            Logger.Log("Log stuff");
            DataRepository.Write("DB stuff");
            ReturnResponse(HttpStatusCode.OK, DateTime.Now.ToString());
        }
        else
            ReturnResponse(HttpStatusCode.BadRequest);
    }
}

BaseHandler:

public abstract class BaseHttpHandler : IHttpHandler
{
    private HttpContext _httpContext;
    private ILogger _logger;
    private IDataRepository _dataRepository;
    protected ILogger Logger { get { return _logger; } }
    protected IDataRepository DataRepository { get { return _dataRepository; } }
    protected HttpContext Context { get { return _httpContext; } }
    protected HttpRequest Request { get { return _httpContext.Request; } }
    protected HttpResponse Response { get { return _httpContext.Response; } }
    protected bool IsRequestFromUAD { get { return Request.UserAgent == null ? false : Request.UserAgent.Equals("UAD"); } }
    public virtual bool IsReusable { get { return false; } }

    public void ProcessRequest(HttpContext context)
    {
        WindsorContainer container = (WindsorContainer)context.Application[0];
        _logger = container.Resolve<ILogger>();
        _dataRepository = container.Resolve<IDataRepository>();

        _httpContext = context;
        ProcessRequest(new HttpContextWrapper(context));
    }

    protected virtual void ReturnResponse(HttpStatusCode httpStatus)
    {
        Response.StatusCode = (int)httpStatus;
    }

    protected virtual void ReturnResponse(HttpStatusCode httpStatus, string response)
    {
        Response.StatusCode = (int)httpStatus;
        Response.Write(response);
    }

    protected virtual string GetInputStream()
    {
        using (var reader = new StreamReader(Request.InputStream))
        {
            return reader.ReadToEnd();
        }
    }

    public abstract void ProcessRequest(HttpContextBase context);
}
+1  A: 

I misread your post. Disregard this answer.

I'm curious where you are calling Dispose() on your repository though.

Frank Schwieterman
Hi Frank. Thanks for your comment. If the BaseHttpHandler implements IHttpHandler shouldn't the ProcessRequest method be called automatically? When I run this code outside unit testing it works fine?
Matt
You did not mark ProcessRequest as virtual. So when the runtime has a pointer to your class as a BaseHttpRequest, it will try to call BaseHttpRequest.ProcessRequest(). When your test has a pointer as a UADTimeHandler, it will try to call the UADTimeHandler.ProcessRequest(). So they have different behavior.
Frank Schwieterman
Hmm well I'm not sure why you're seeing that behavior, since the runtime will reference it as a IHttpHandler not a BaseHttpHandler. I wonder if your test would behave differently if UADHandlerFixture._handler were of type IHttpHandler instead of BaseHttpHandler.
Frank Schwieterman
correction: type IHttpHandler instead of UADTimeHttpHandler
Frank Schwieterman
Oh I've been terribly daft here. I didn't realize you had overloaded ProcessRequest here, one takes a HttpContext and one takes a HttpContextBase. The problem is your test is calling ProcessRequest(HttpContextBase) on your derived class, not ProcessRequest(HttpContext) on the base class.
Frank Schwieterman
Hi Frank. That's right. But if I call the base method I can't pass in the mocked HttpContextBase?
Matt
That's true. Quite the pickle. You could extract method from BaseHttpHandler.ProcessRequest() which takes a HttpContextBase as input. Then the original BaseHttpHandler.ProcessRequest() could use HttpContextWrapper to pass the httpContext to the extracted method (your test would then call the extracted method).
Frank Schwieterman
Hi Frank. What I did to get this to work was to remove the abstract ProcessReqest method from the base class and create a virtual Process method instead: public virtual void Process(HttpContextBase context) { _httpContext = context; WindsorContainer container = (WindsorContainer)_httpContext.Application[0]; _logger = container.Resolve<ILogger>(); _dataRepository = container.Resolve<IDataRepository>(); }Then in the derived class override it and call base.Process(context)
Matt
+1 for the work and leaving the stub post here until it's all gone
Ruben Bartelink
Not sure what that means but thanks!
Matt