Search code examples
c#unit-testingmoqxunit

Unit Test: Mocked service returns default boolean (false) despite Returns() set to true. C# xunit moq


I have been asked to unit test the following controller in xunit using moq (C# .Net Core app 3.1):

    private readonly IConfigService _configService;
    private readonly IOptions<ApiVersion> _apiVersionSettings;
    private readonly IOptions<MinRequiredDatabaseVersion> _minRequiredDatabaseVersion;

    public InfoController(IConfigService configService, IOptions<ApiVersion> apiVersionSettings, IOptions<MinRequiredDatabaseVersion> minRequiredDatabaseVersion)
    {
        _configService = configService;
        _apiVersionSettings = apiVersionSettings;
        _minRequiredDatabaseVersion = minRequiredDatabaseVersion;
    }

    [HttpGet]
    [ProducesResponseType(typeof(ApplicationVersionDto), 200)]
    [ProducesResponseType(typeof(BadRequestResult), 400)]
    public IActionResult GetVersions()
    {
        // get db version
        var dbVersion = _configService.GetDbVersions();
        // get api version
        var apiVersion = _apiVersionSettings.Value.Version;
        var minReqiredDbVersion = new MinRequiredDataVersion(_minRequiredDatabaseVersion.Value.Major, _minRequiredDatabaseVersion.Value.Minor, _minRequiredDatabaseVersion.Value.BuildNumber);

        var isDatabaseRightVersion = _configService.hasWebSolutionTheRightDatabase(dbVersion, minReqiredDbVersion);
        string currentDbVersion = dbVersion.MajorVersion + "." + dbVersion.MinorVersion + "." + dbVersion.BuildNumber;
        string minDbVersion = minReqiredDbVersion.MajorVersion + "." + minReqiredDbVersion.MinorVersion + "." + minReqiredDbVersion.BuildNumber;
        if (!isDatabaseRightVersion) 
            throw new CustomGisException(CustomGisExceptionName.ArgumentException, 202011101419083007, $"Update the database! current database version {currentDbVersion}, but should have been min. {minDbVersion}", $"Update the database! current database version {currentDbVersion}, but should have been min. {minDbVersion}");

        var result = new ApplicationVersionDto(dbVersion, apiVersion);
        return Json(result);
    }

After setting up the mocks, the mocked Database Version service (_minRequiredDatabaseVersion) returns the default boolean value false even though the mock is set to return true, indicating that something is pear shaped:

    [Fact]
    public void GetVersionsGet_ReturnsJsonResult_WhenInvoked()
    {
        // Arrange
        var mockVwCurrentVersionInfo = Mock.Of<VwCurrentVersionInfo>(x => x.BuildNumber == 988 && x.MajorVersion == 988 && x.MinorVersion == 988);
        fixture.mockApiVersion.SetupGet(o => o.Value).Returns(new ApiVersion(){});
        fixture.mockMinRequiredDatabaseVersion.SetupGet(o => o.Value).Returns(new MinRequiredDatabaseVersion(){
            Major=888,
            Minor=888,
            BuildNumber=888});
        fixture.mockConfigService.Setup(x => x.GetDbVersions()).Returns(mockVwCurrentVersionInfo);
        fixture.mockConfigService.Setup(x => x.hasWebSolutionTheRightDatabase(mockVwCurrentVersionInfo, fixture.mockMinRequiredDataVersion.Object)).Returns(true);

        // Act
        var result = fixture.controller.GetVersions();
        var jsonResult = result as JsonResult;

        // Assert
        // Assertions here.
    }

When debugging I reach the line if(!isDatabaseRightVersion) in the controller, which throws the exception.

How can I return the boolean true in this mocked service?

Here is my fixture:

public InfoController controller;
public Mock<IConfigService> mockConfigService;
public Mock<IOptions<ApiVersion>> mockApiVersion;
public Mock<IOptions<MinRequiredDatabaseVersion>> mockMinRequiredDatabaseVersion;
public Mock<VwCurrentVersionInfo> mockVwCurrentVersionInfo;
public Mock<MinRequiredDataVersion> mockMinRequiredDataVersion;
public int vurderingsejendomIdToBeFound;

public InfoFixture()
{
    // Mock services and their setups.
    mockConfigService = new Mock<IConfigService>();
    mockApiVersion = new Mock<IOptions<ApiVersion>>();
    mockMinRequiredDatabaseVersion = new Mock<IOptions<MinRequiredDatabaseVersion>>();
    mockVwCurrentVersionInfo = new Mock<VwCurrentVersionInfo>();
    mockMinRequiredDataVersion = new Mock<MinRequiredDataVersion>();
    mockMinRequiredDataVersion.Object.MajorVersion = 5;
    mockMinRequiredDataVersion.Object.MinorVersion = 5;
    mockMinRequiredDataVersion.Object.BuildNumber = 5;

    // Controller
    controller = new InfoController(mockConfigService.Object, mockApiVersion.Object, mockMinRequiredDatabaseVersion.Object);
}

public void Dispose() {}

Thanks in advance for your valuable feedback.


Solution

  • In your setup

       fixture.mockConfigService
        .Setup(x => x.hasWebSolutionTheRightDatabase(mockVwCurrentVersionInfo, fixture.mockMinRequiredDataVersion.Object))
        .Returns(true);
    

    fixture.mockMinRequiredDataVersion.Object is not equal to minReqiredDbVersion

    As an option you can use It.IsAny<T> instead of fixture.mockMinRequiredDataVersion.Object:

          fixture.mockConfigService
        .Setup(x => x.hasWebSolutionTheRightDatabase(mockVwCurrentVersionInfo,It.IsAny< MinRequiredDataVersion >() ))
        .Returns(true);
    

    This way you mock will work for any instance of MinRequiredDataVersion

    I you need to make sure that minReqiredDbVersion has specific version, you can capture that parameter with callback:

    MinRequiredDatabaseVersion capturedMinReqiredDbVersion = null;
    
    fixture.mockConfigService
            .Setup(x => x.hasWebSolutionTheRightDatabase(mockVwCurrentVersionInfo,It.IsAny< MinRequiredDataVersion >() ))
            .Callback( (dbVersion, minReqiredDbVersion) => {capturedMinReqiredDbVersion = minReqiredDbVersion; })  
            .Returns(true);
    
    // Assert
    // Assert capturedMinReqiredDbVersion here