Search code examples
c#moqautofixture

C# unit testing mocking service ignoring return


I am writing some unit tests to test a controller. In that controller there is a call to a service. In my test I want to mock the service call and obviously specify the desired return.

When the code runs it goes into the controller and when it reaches the service I can clearly see that it is using my mock. However, the return value of the mock is always null and not the return that I specified (i.e. expectedItem). Any idea?

Unit test against controller's action

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

Names have been abbreviated for brevity.

System Under Test

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

Solution

  • One key point here is that you're using AutoFixture to create both your Mock and your service. In order to ensure that you're using the same mock instance for your Setup as the one that got injected into the service, you'll probably want to Freeze the mock instance prior to creating the service.

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

    Note that I captured the result of the Freeze so it's easier to use in test methods. This is a pattern I like, but you could theoretically continue using _fixture.Create<>() in your methods if you prefer not to have another private field hanging about.