Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access HttpContext inside a unit test in ASP.NET 5 / MVC 6

Lets say I am setting a value on the http context in my middleware. For example HttpContext.User.

How can test the http context in my unit test. Here is an example of what I am trying to do

Middleware

public class MyAuthMiddleware
{
    private readonly RequestDelegate _next;

    public MyAuthMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        context.User = SetUser(); 
        await next(context);
    }
}

Test

[Fact]
public async Task UserShouldBeAuthenticated()
{
    var server = TestServer.Create((app) => 
    {
        app.UseMiddleware<MyAuthMiddleware>();
    });

    using(server)
    {
        var response = await server.CreateClient().GetAsync("/");
        // After calling the middleware I want to assert that 
        // the user in the HttpContext was set correctly
        // but how can I access the HttpContext here?
    }
}
like image 838
Sul Aga Avatar asked May 31 '15 12:05

Sul Aga


2 Answers

The RC1 version of asp.net 5/MVC6 makes it possible to set HttpContext manually in Unit Tests, which is awesome!

        DemoController demoController = new DemoController();
        demoController.ActionContext = new ActionContext();
        demoController.ActionContext.HttpContext = new DefaultHttpContext();
        demoController.HttpContext.Session = new DummySession();

DefaultHttpContext class is provided by the platform. DummySession can be just simple class that implements ISession class. This simplifies things a lot, because no more mocking is required.

like image 118
Tuukka Lindroos Avatar answered Sep 23 '22 04:09

Tuukka Lindroos


It would be better if you unit test your middleware class in isolation from the rest of your code.

Since HttpContext class is an abstract class, you can use a mocking framework like Moq (adding "Moq": "4.2.1502.911", as a dependency to your project.json file) to verify that the user property was set.

For example you can write the following test that verifies your middleware Invoke function is setting the User property in the httpContext and calling the next middleware:

[Fact]
public void MyAuthMiddleware_SetsUserAndCallsNextDelegate()
{
    //Arrange
    var httpContextMock = new Mock<HttpContext>()
            .SetupAllProperties();
    var delegateMock = new Mock<RequestDelegate>();
    var sut = new MyAuthMiddleware(delegateMock.Object);

    //Act
    sut.Invoke(httpContextMock.Object).Wait();

    //Assert
    httpContextMock.VerifySet(c => c.User = It.IsAny<ClaimsPrincipal>(), Times.Once);
    delegateMock.Verify(next => next(httpContextMock.Object), Times.Once);
}

You could then write additional tests for verifying the user has the expected values, since you will be able to get the setted User object with httpContextMock.Object.User:

Assert.NotNull(httpContextMock.Object.User);
//additional validation, like user claims, id, name, roles
like image 37
Daniel J.G. Avatar answered Sep 21 '22 04:09

Daniel J.G.