Search code examples
c#unit-testingautofixture

Mocking constructor dependencies using AutoMoq attribute


I'm wondering if there is a way of setting up a mock for a dependency before the constructor of the System Under Test (SUT) is called when using a test case that sets up AutoData.

My SUT looks like:

class Sut
{
    private readonly IFoo foo;
    public Sut(IFooFactory factory)
    {
        this.foo = factory.Build(1, 2);
    }

    public IFoo Foo
    {
        get
        {
            return this.foo;
        }
    }
}

So the test that I'm writing looks like:

[Theory]
[AutoData]
internal void Foo_IsCorrectlySet_Test(
    [Frozen] Mock<IFooFactory> fooFactory,
    IFoo foo,
    Sut sut)
{
    fooFactory.Setup(mock => mock.Build(1, 2))
        .Returns(foo)
        .Verifiable();

    var actual = sut.Foo;

    Assert.Equal(foo, sut);
    fooFactory.Verify();
}

Obviously this test fails as the constructor to the Sut runs before I am able to setup the IFooFactory. So I thought that I may have been able to change the declaration of the Sut to Lazy<Sut> in the test. But again the constructor is still run before the actual test code is run meaning that my test is going to fail.

Now I know that I could easily setup this test with an actual Fixture object and create all of my objects manually and setting them up before I call to create the Sut which is fine but I'm wanting to keep my tests all roughly the same therefore I'm wondering if there is a way that I could still setup my test with the AutoData attribute but not run the constructor until after everything is setup?


Solution

  • AutoFixture was originally build as a tool for Test-Driven Development (TDD), and TDD is all about feedback. In the spirit of GOOS, you should listen to your tests. If the tests are hard to write, you should consider your API design. AutoFixture tends to amplify that sort of feedback, which may also be the case here.

    Consider the invariants of the Sut class. Since it has a read-only IFoo class field, I'd interpret this as a strong indication that IFoo is a dependency of the class.

    If that's the case, then inject IFoo via the constructor, instead of IFooFactory:

    public class Sut
    {
        private readonly IFoo foo;
        public Sut(IFoo foo)
        {
            this.foo = foo;
        }
    
        public IFoo Foo
        {
            get { return this.foo; }
        }
    }
    

    You can still compose it using IFooFactory in the application's Composition Root:

    var sut = new Sut(aFactory.Build(1, 2));
    

    This will make the tests easier to write. I can't even show you how the above test would look with this refactoring, because it'd be redundant and can (and should) be deleted.

    FWIW, the original design proposed above violates Nikola Malovic's 4th law of IoC that constructors should do no work.