0

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

2 Answers2

0

You are doing DI wrong, you are not injecting Repository into Your serice. Try like this.

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

    public class Service : IService
    {
        IRepository Repository;
        public Service(IRepository repository)
        {
            this.Repository = repository;
        }
        public string GetStringFromInt()
        {
            return Repository.GetInt().ToString();
        }
    }

Now when you mock IRepository, you can add it to Service.

You are using a new Repository() in constructor, so you are using that implementation

Djuro
  • 384
  • 2
  • 9
0

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...

Emma Middlebrook
  • 836
  • 1
  • 9
  • 19