I’m trying to test a class that takes a factory (Func<T>) and I’m using Moq and AutoFixture.
What is the best way to setup the “environment” to see if the factory has been used and how many times and what methods have been used on the returned instances?
Currently I’m Mock’ing the T and Injecting a Func<T> that keeps count of all returned Mock instances:
public class SystemUnderTest {
public SystemUnderTest(Func<IMyClass> c)
{
try {
var c1 = c();
c1.Name="n1";
c1.Send();
}
catch(Exception){
var c2 = c();
c2.Name="n2";
c2.Send();
}
}
}
private Mock<IMyClass> MockFactory()
{
var m = new Mock<IMyClass>();
m.SetupProperty(mc=>mc.Name);
_returnedStubs.Add(m);
return m;
}
[Test]
public void TestSomething()
{
var fixture = new Fixture();
fixture.Inject(()=>MockFactory().Object)
var sut = fixture.CreateAnonymous<SystemUnderTest>();
Assert.That(_returnedStubs.Count,Is.Equal(1));
_returnedStubs[0].Verify(m=>m.Send(),Times.Exactly(1));
_returnedStubs[0].Verify(m=>m.Name = "n1");
}
But it feels kinda iffy/ugly to me. And I’m pretty sure that an instance variable in a test class is a dangerous thing
Since AutoFixture is able to create anonymous delegates, when asked to create an anonymous instance of
SystemUnderTest, it will also automatically provide an anonymousFunc<IMyClass>delegate, which in turn returns an anonymous instance ofIMyClasswhen invoked.This means that, given this scenario:
the following code:
will assign the
c1andc2variables with anonymous instances ofIMyClass. Furthermore, if you configure AutoFixture to work as an auto-mocking container, for example using theAutoMoqCustomization, those anonymous instances ofIMyClasswill also happen to be Moq proxies:This information however, although useful, doesn’t really help you in your particular case since you need to get a hold of the mock objects returned by the
Func<IMyClass>factory method in your test, in order to configure their behavior and make some assertions on how they’ve been interacted with.The best solution, in my opinion, is to change the implementation of the factory method from
Func<IMyClass>to an interface. This way you can create a fake factory that returns different mocks of theIMyClassinterface when theCreatemethod is invoked multiple times in a sequence:So, given this example:
You can setup your test scenario as follows:
Note that the
ReturnsInOrderis a custom extension method that uses theCallbackmethod in Moq to return different values from a stubbed method when it gets invoked multiple times in a row.