7

ASP.NET Core Unit Test: How to Mock HttpContext.Features.Get()

 3 years ago
source link: https://edi.wang/post/2021/4/29/aspnet-core-unit-test-how-to-mock-httpcontextfeaturesget
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

ASP.NET Core Unit Test: How to Mock HttpContext.Features.Get()

Thursday, April 29, 2021 China Standard Time - 1 Reads

In ASP.NET Core unit tests, if you want to mock HttpContext.Features.Get<SomeType>(), here's the trick.

Problem


I have my Error page code that will get exception detail infomation, to do that, I use HttpContext.Features.Get<IExceptionHandlerPathFeature>().

public void OnGet()
{
    var requestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
    if (exceptionFeature is not null)
    {
        // Get which route the exception occurred at
        var routeWhereExceptionOccurred = exceptionFeature.Path;

        // Get the exception that occurred
        var exceptionThatOccurred = exceptionFeature.Error;
        _logger.LogError($"Error: {routeWhereExceptionOccurred}, " +
                         $"client IP: {HttpContext.Connection.RemoteIpAddress}, " +
                         $"request id: {requestId}", exceptionThatOccurred);
    }

    RequestId = requestId;
}

Now I want to unit test this piece of code. Usually I will use DefaultHttpContext instance in unit tests that requires an HttpContext for a page or controller. But I found the Features property is readonly on the HttpContext class. So there's no way to assign values that we mocked to this property.

namespace Microsoft.AspNetCore.Http
{
    public abstract class HttpContext
    {
        protected HttpContext();

        //
        // Summary:
        //     Gets the collection of HTTP features provided by the server and middleware available
        //     on this request.
        public abstract IFeatureCollection Features { get; }
		
        //  ...
    }
}

Solution


First, prepare the mock as usual. In my case, I set up IFeatureCollection.Get() method to return my desired object.

var mockIFeatureCollection = _mockRepository.Create<IFeatureCollection>();
mockIFeatureCollection.Setup(p => p.Get<IExceptionHandlerPathFeature>())
    .Returns(new ExceptionHandlerFeature
    {
        Path = "/996/icu",
        Error = new("Too much fubao")
    });
httpContextMock.Setup(p => p.Features).Returns(mockIFeatureCollection.Object);

Then, in order to assign values to HttpContext.Features, we can't use DefaultHttpContext this time. We have to create a mock for HttpContext. And set up the Features property to return our mocked IFeatureCollection object.

var httpContextMock = _mockRepository.Create<HttpContext>();
httpContextMock.Setup(p => p.Features).Returns(mockIFeatureCollection.Object);

Now, run the unit test, we can see values are coming up correctly.

img-e2d741da-b772-468e-aa65-62b1638fc69b.png


This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK