Search code examples
c#autofixturemoq-3automoq

AutoFixture with AutoMoq and concrete object injection


I'm facing a strange problem related to AutoFixture and AutoMoqCustomization and how it deals with automocking of concrete classes. I suspect that I'm not using it very well but would like to know what's the problem. First of all her's some context. Let's say I have a class that I want to test :

public class IdentityApplicationService
{
    public IdentityApplicationService(
        TenantProvisioningService tenantProvisioningService)
    {
        // guard clause etc.
        _tenantProvisioningService = tenantProvisioningService;
    }
}

and its dependency class TenantProvisioningService (TenantProvisioningService's dependencies are not relevant here because they will be auto mocked and I don't care about in my test):

public class TenantProvisioningService
{
    readonly IRoleRepository _roleRepository;
    readonly ITenantRepository _tenantRepository;
    readonly IUserRepository _userRepository;

    public TenantProvisioningService(
        ITenantRepository tenantRepository,
        IUserRepository userRepository,
        IRoleRepository roleRepository)
    {
        this._roleRepository = roleRepository;
        this._tenantRepository = tenantRepository;
        this._userRepository = userRepository;
    }
}

and here's my simple test :

[Fact]
public void ShouldReturnTenantWhenCallingProvisionTenant()
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var mockTenantProvisioningService =
        fixture.Freeze<Mock<TenantProvisioningService>>();
    var sut = fixture.Create<IdentityApplicationService>();
    var command = new ProvisionTenantCommand(
        "bla",
        "bla SaaS platform",
        "superadmin",
        "superadmin",
        "[email protected]",
        null,
        null,
        null,
        null,
        null,
        null,
        null);
    var tenant = sut.ProvisionTenant(command);

    // some asserts
}

This doesn't work because when I call fixture.Create<IdentityApplicationService>() then in it's constructor a concrete TenantProvisioningService is injected instead of a proxied one that you can find in mockTenantProvisioningService.Object.

If I rewrite the test like this (note the fixture inject line) everything works as expected (by me at least :))

[Fact]
public void ShouldReturnTenantWhenCallingProvisionTenant()
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var mockTenantProvisioningService =
        fixture.Freeze<Mock<TenantProvisioningService>>();
    fixture.Inject(mockTenantProvisioningService.Object);
    var sut = fixture.Create<IdentityApplicationService>();
    var command = new ProvisionTenantCommand(
        "bla",
        "bla SaaS platform",
        "superadmin",
        "superadmin",
        "[email protected]",
        null,
        null,
        null,
        null,
        null,
        null,
        null);
    var tenant = sut.ProvisionTenant(command);

    // some asserts
}

So my question is : Am I doing it wrong or is it the way it should be? If not please give me the explanation why AutoFixture is behaving like this.


Solution

  • As Mark Seemann points out, this is the expected behaviour.

    Below is the code from the original post updated to work with the current version of AutoFixture:

    Func<ISpecimenBuilder, bool> concreteFilter = 
        sb => !(sb is MethodInvoker);
    
    var relays = new FilteringRelays(concreteFilter);
    
    var fixture = new Fixture(relays).Customize(
        new AutoMoqCustomization(
            new MockRelay(
                new TrueRequestSpecification())));
    

    The FilteringRelays class remains the same.