Search code examples
c#xunitautofixtureautomoq

Mocked method do not pass correct value


I am trying to understand how mocking works in Xunit with AutoFixture. I have created Service and Repository classes and their interfaces. Mocked method should pass value which is different from default value.

Mocked method always pass default values instead of values which i am writing in ".Returns()". I have tried AutoConfiguredMoqCustomization but it provides completely random values which i can't get back.

Repository.cs

public class Repository : IRepository
{
    public int GetInt()
    {
         return 999;
    }
}

Service.cs

public class Service : IService
{        
    private readonly Repository _repository;

    public Service()
    {
        _repository = new Repository();
    }

    public string GetStringFromInt()
    {
        return _repository.GetInt().ToString();
    }
}

Test

    [Fact]
    public void Test()
    {
        var fixture = new Fixture().Customize(new AutoMoqCustomization());
        var repositoryMock = fixture.Create<Mock<IRepository>>();
        var service = fixture.Create<Service>();

        repositoryMock.Setup(x => x.GetInt()).Returns(1);
        var act = service.GetStringFromInt();

        Assert.Equal("1", act);
    }

As you see value by default in Repository is 999 and I am expecting 1 from repositoryMock but result is "999" instead of "1".

Ow I have understood my problem. When I declare parameters with auto moq testing service must be AFTER all mocked repositories

Test

[Theory, AutoMoqData]
public void Test([Frozen] Mock<IRepository> repositoryMock, Service service)
{
    ...
}

Attribute

public class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute() : base(GetDefaultFixture)
    {
    }

    private static IFixture GetDefaultFixture()
    {
        return new Fixture().Customize(new AutoMoqCustomization());
    }
}

Solution

  • You should freeze your mock first. When you call Create on AutoFixture, it will create you a new instance every time. Try the following in the modified code (where you are using an interface of the type in your constructor).

    public class ServiceTests
    {
      private readonly IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());
    
      public ServiceTests() 
      {
        fixture.Register<IService>(() => fixture.Create<Service>());
      }
    
      [Fact]
      public void Test()
      {
        // Arrange
        var repositoryMock = fixture.Freeze<Mock<IRepository>>();
        repositoryMock.Setup(x => x.GetInt()).Returns(1);
    
        var service = fixture.Create<IService>();
    
        // Act
        var act = service.GetStringFromInt();
    
        // Verify
        Assert.Equal("1", act);
      }
    }
    

    To check that you have set up autofixture correctly, you can try the following in the unit test in future.

    
    var repo1 = fixture.Create<IRepository>();
    var repo2 = fixture.Create<IRepository>();
    
    Assert.Equal(repo1.GetHashCode(), repo2.GetHashCode());
    

    If the above fails, that indicates that you have not frozen a type. These lines of code have saved me so much head scratching in the past...