Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock HttpActionContext for Unit Test

I have a custom authorization attribute seen below and I am trying to write a unit test to test its functionality.

    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        if (actionContext.Request.Headers.Authorization != null)
        {
            // get the Authorization header value from the request and base64 decode it
            string userInfo = Encoding.Default.GetString(Convert.FromBase64String(actionContext.Request.Headers.Authorization.Parameter));

            // custom authentication logic
            if (string.Equals(userInfo, string.Format("{0}:{1}", "user", "pass")))
            {
                IsAuthorized(actionContext);
            }
            else
            {
                HandleUnauthorizedRequest(actionContext);
            }
        }
        else
        {
            HandleUnauthorizedRequest(actionContext);
        }
    }

    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized)
        {
            ReasonPhrase = "Unauthorized"
        };
    }

My problem is that when I try to test this I get "System.NullReferenceException: Object reference not set to an instance of an object." I have tried to set the actionContext's request.headers.authorization value but it has no setter. When I try mocking the HttpActionContext it says it cannot convert from a mock HttpActionContext to a real one. Below is my test code

public class HttpBasicAuthorizeAttributeTest
{
    private HttpBasicAuthorizeAttribute ClassUnderTest { get; set; }

    private HttpActionContext actionContext { get; set; }

    [TestMethod]
    public void HttpBasicAuthorizeAttribute_OnAuthorize_WithAuthorizedUser_ReturnsAuthorization()
    {
       var context = new Mock<HttpActionContext>();
       context.Setup(x => x.Request.Headers.Authorization.Parameter).Returns("bzUwkDal=");
       ClassUnderTest.OnAuthorization(context);
    }

    [TestInitialize]
    public void Initialize()
    {
        ClassUnderTest = new HttpBasicAuthorizeAttribute();
        actionContext = new HttpActionContext();
    }
}

*Left out the assert until I can even get the HttpActionContext to work

like image 513
john smith Avatar asked Aug 25 '17 19:08

john smith


1 Answers

You can use the actual objects and provide it to the mock in order to exercise the method under test as Moq in unable to mock the non-virtual members.

[TestMethod]
public void HttpBasicAuthorizeAttribute_OnAuthorize_WithAuthorizedUser_ReturnsAuthorization() {
   //Arrange
    var context = new HttpActionContext();
    var headerValue = new AuthenticationHeaderValue("Basic", "bzUwkDal=");
    var request = new HttpRequestMessage();
    request.Headers.Authorization = headerValue;
    var controllerContext = new HttpControllerContext();
    controllerContext.Request = request;
    context.ControllerContext = controllerContext;

   //Act
   ClassUnderTest.OnAuthorization(context);

   //Assert
   //...
}
like image 101
Nkosi Avatar answered Nov 06 '22 15:11

Nkosi