本文介绍了在单元测试中模拟IHttpContextAccessor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种使用IHttpContextAccessor

public class HeaderConfiguration : IHeaderConfiguration
{
    public HeaderConfiguration()
    {

    }

    public string GetTenantId(IHttpContextAccessor httpContextAccessor)
    {
        return httpContextAccessor.HttpContext.Request.Headers["Tenant-ID"].ToString();
    }
}

我正在测试GetBookByBookId方法

让我们说这个方法看起来像这样:

Let's say the method looks like this:

public class Book
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private IHeaderConfiguration _headerConfiguration;
    private string _tenantID;

    public Book(IHeaderConfiguration headerConfiguration, IHttpContextAccessor httpContextAccessor){
        var headerConfig = new HeaderConfiguration();
        _httpContextAccessor = httpContextAccessor;
        _tenantID = headerConfig.GetTenantId(_httpContextAccessor);
    }

    public Task<List<BookModel>> GetBookByBookId(string id){
        //do something with the _tenantId
        //...
    }
}

这是我对GetBookByBookId方法的单元测试

Here's my unit test for GetBookByBookId method

[Fact]
public void test_GetBookByBookId()
{
    //Arrange

    //Mock IHttpContextAccessor
    var mockHttpContextAccessor = new Mock<IHttpContextAccessor>();

    mockHttpContextAccessor.Setup(req => req.HttpContext.Request.Headers["Tenant-ID"].ToString()).Returns(It.IsAny<string>());
    //Mock HeaderConfiguration
    var mockHeaderConfiguration = new Mock<IHeaderConfiguration>();
    mockHeaderConfiguration.Setup(x => x.GetTenantId(mockHttpContextAccessor.Object)).Returns(It.IsAny<string>());

    var book = new Book( mockHttpContextAccessor.Object, mockHeaderConfiguration.Object);

    var bookId = "100";

    //Act
    var result = book.GetBookByBookId(bookId);

    //Assert
    result.Result.Should().NotBeNull().And.
        BeOfType<List<BookModel>>();
}

但是对于这一行:

mockHttpContextAccessor.Setup(req => req.HttpContext.Request.Headers["Tenant-ID"].ToString()).Returns(It.IsAny<string>());

我想知道使用标头值模拟IHttpContextAccessor的正确方法是什么?

I was wondering what's the proper way to mock IHttpContextAccessor with header value?

推荐答案

您可以将DefaultHttpContext用作IHttpContextAccessor.HttpContext的后盾.节省您设置太多事情的麻烦

You can use the DefaultHttpContext as a backing for the IHttpContextAccessor.HttpContext. Saves you having to set-up too many things

接下来,您不能将It.IsAny<string>()用作Returns结果.它们只能在设置表达式中使用.

Next you cannot use It.IsAny<string>() as a Returns result. They were meant to be used in the set up expressions alone.

检查重构

[Fact]
public async Task test_GetBookByBookId() {
    //Arrange

    //Mock IHttpContextAccessor
    var mockHttpContextAccessor = new Mock<IHttpContextAccessor>();
    var context = new DefaultHttpContext();
    var fakeTenantId = "abcd";
    context.Request.Headers["Tenant-ID"] = fakeTenantId;
    mockHttpContextAccessor.Setup(_ => _.HttpContext).Returns(context);
    //Mock HeaderConfiguration
    var mockHeaderConfiguration = new Mock<IHeaderConfiguration>();
    mockHeaderConfiguration
        .Setup(_ => _.GetTenantId(It.IsAny<IHttpContextAccessor>()))
        .Returns(fakeTenantId);

    var book = new Book(mockHttpContextAccessor.Object, mockHeaderConfiguration.Object);

    var bookId = "100";

    //Act
    var result = await book.GetBookByBookId(bookId);

    //Assert
    result.Should().NotBeNull().And.
        BeOfType<List<BookModel>>();
}

被测类可能还会出现问题,因为它实际上应该显式注入时手动初始化HeaderConfiguration.

There may also be an issue with the Class Under Test as it is manually initializing the HeaderConfiguration when it should actually be explicitly injected.

public Book(IHeaderConfiguration headerConfiguration, IHttpContextAccessor httpContextAccessor) {
    _httpContextAccessor = httpContextAccessor;
    _tenantID = headerConfiguration.GetTenantId(_httpContextAccessor);
}

这篇关于在单元测试中模拟IHttpContextAccessor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 21:01