C# 单元测试模拟服务忽略 return

C# unit testing mocking service ignoring return

我正在编写一些单元测试来测试控制器。在那个控制器中有一个服务调用。在我的测试中,我想模拟服务调用并显然指定所需的 return.

当代码运行时,它进入控制器,当它到达服务时,我可以清楚地看到它正在使用我的模拟。但是,mock 的 return 值始终为空,而不是我指定的 return(即 expectedItem)。有什么想法吗?

针对控制器操作的单元测试

public class SearchIATeamControllerTests : IDisposable
{
    private readonly SearchIATeamController _sut;
    private IFixture _fixture;

    public SearchIATeamControllerTests()
    {
        _fixture = new Fixture().Customize(new AutoMoqCustomization());
        _sut = _fixture.Create<SearchIATeamController>();
    }


    [Fact]
    public async Task Get_team_name_with_ia_team_name_returns_ok()
    {
        // Arrange
        var expectedResultItem = _fixture.Create<SearchIATeamResponse>();

        var expectedItem = new List<SearchIATeamResponse>
        {
            expectedResultItem
        };

        var mockIATeamService = _fixture.Create<Mock<IIATeamSearchService>>();
        mockIATeamService.Setup(m => m.GetIATeamName(It.IsAny<string>())).ReturnsAsync(expectedItem);

        // Act
        var result = await _sut.Get("test").ConfigureAwait(false);
    }
} 

为简洁起见,名称已缩写。

被测系统

public async Task<ActionResult<SearchIATeamResponse>> Get([FromQuery] string iATeamName)
{   
    if (iATeamName == null)
    {
        return BadRequest();
    }

    try
    {
        var result = await _searchIATeamService.GetIATeamName(iATeamName);

        if (!result.Any())
        {
            return NotFound();
        }

        return Ok(result);

     }
     catch (ArgumentException ex)
     {
         return BadRequest(ex.Message);
     }      
}

这里的一个关键点是您正在使用 AutoFixture 创建 Mock 和服务。为了确保您在设置中使用与注入到服务中的相同的模拟实例,您可能希望在创建服务之前 Freeze 模拟实例。

public class SearchIATeamControllerTests : IDisposable
{
    private readonly SearchIATeamController _sut;
    private readonly Mock<IIATeamSearchService> _mockIATeamService;
    private IFixture _fixture;

    public SearchIATeamControllerTests()
    {
        _fixture = new Fixture().Customize(new AutoMoqCustomization());
        _mockIATeamService = _fixture.Freeze<Mock<IIATeamSearchService>>();
        _sut = _fixture.Create<SearchIATeamController>();
    }


    [Fact]
    public async Task Get_team_name_with_ia_team_name_returns_ok()
    {
        // Arrange
        var expectedResultItem = _fixture.Create<SearchIATeamResponse>();

        var expectedItem = new List<SearchIATeamResponse>
        {
            expectedResultItem
        };

        _mockIATeamService.Setup(m => m.GetIATeamName(It.IsAny<string>())).ReturnsAsync(expectedItem);

        // Act
        var result = await _sut.Get("test").ConfigureAwait(false);
    }
} 

请注意,我捕获了 Freeze 的结果,因此更易于在测试方法中使用。这是我喜欢的模式,但如果您不想让另一个私有字段闲置,理论上您可以继续在您的方法中使用 _fixture.Create<>()

问题是由顺序引起的 - 控制器只能在模拟服务设置后声明,而不是在构造函数中声明。