Search code examples
c#unit-testingautofixtureautomoq

Constructor with more than one instance of same type


I have a class with a constructor like this:

MyClass(MySetting, IMyService, IMyService, IMyService)

How can I use AutoFixture to create MyClass in this case? I know when it has only one IMyService param, we can use AutoMoq to Freeze a mock, but in this case I'm not sure we can Freeze three mocks because I think the last one will be used for all three parameters.


Solution

  • Indeed, if you Freeze an object, you'll get the same object every time you ask for it; that's the point of Freeze.

    What I usually do in such a situation is to add Inspection Properties to the class, because What you compose, you can also expose:

    public class MyClass
    {
        public MyClass(
            MySetting setting,
            IMyService service1,
            IMyService service2,
            IMyService service3)
        {
            this.Service1 = service1;
            this.Service2 = service2;
            this.Service3 = service3;
        }
    
        public IMyService Service1 { get; }
        public IMyService Service2 { get; }
        public IMyService Service3 { get; }
    
        public string DoIt()
        {
            return
                this.Service1.Whatever() +
                this.Service2.Whatever() +
                this.Service3.Whatever();
        }
    }
    

    You can use Mock.Get to get the Mock for each injected service, like demonstrated by this test:

    [Fact]
    public void AskTheSut()
    {
        var fixture = new Fixture().Customize(new AutoMoqCustomization());
        var sut = fixture.Create<MyClass>();
        Mock.Get(sut.Service1).Setup(s => s.Whatever()).Returns("foo");
        Mock.Get(sut.Service2).Setup(s => s.Whatever()).Returns("bar");
        Mock.Get(sut.Service3).Setup(s => s.Whatever()).Returns("baz");
    
        var actual = sut.DoIt();
    
        Assert.Equal("foobarbaz", actual);
    }
    

    On a tangential note, as a design principle I'd say that one dependency is fine, two of the same dependency can also occasionally be appropriate, but if you have three, you should consider having a collection of them instead. (One, two, many...)