ASP.NET Core 单元测试:如何 Mock HttpContext.Features.Get()

2021-05-27 14:37:21 浏览数 (1)

导语

在 ASP.NET Core 里,如果你想单元测试 HttpContext.Features.Get<SomeType>(),这个技巧一定不要错过。

问题

我有个 Error 页面,需要取得异常的详细信息。我使用 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;

}

现在,我需要单元测试这段代码。通常,在需要 HttpContext的 Page 或 Controller 中,我会使用 DefaultHttpContext 的实例。但我发现 HttpContext 上的 Features 属性是只读的。因此没有办法将 mock 好的对象赋值给它。

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

// ...

}

}

解决办法

首先,像平常一样准备 mock。在我的案例里,我需要配置 IFeatureCollection.Get() 方法,返回我想要的对象。

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

下下来,为了给 HttpContext.Features 赋值,我们这次不能使用 DefaultHttpContext 了。我们需要创建 HttpContext 自己的 mock,并且配置 Features 属性返回刚才 mock 的 IFeatureCollection 对象。

var httpContextMock = _mockRepository.Create<HttpContext>();

httpContextMock.Setup(p => p.Features).Returns(mockIFeatureCollection.Object);

现在运行单元测试,我们可以看到正确的值已经输出了。

0 人点赞