Search code examples
c#unit-testingmoqxunitautofixture

Exception when using more than two mocks in a test


I am writing a test using xUnit 2 and AutoFixture for a .Net Core 2.2 project. I require three Mocks in the test to satisfy the system under test and previously AutoFixture had no problem doing this. However now when I add more than two mocks to the test signature I get an exception.

[Theory]
[AutoData]
public void ContrivedTest(
   Mock<IDependencyOne> mockDependencyOne,
   Mock<IDependencyTwo> mockDependencyTwo)
{
    Assert.True(true);
}

Will work as expected, but:

[Theory]
[AutoData]
public void ContrivedTest(
   Mock<IDependencyOne> mockDependencyOne,
   Mock<IDependencyTwo> mockDependencyTwo,
   Mock<IDependencyThree> mockDependencyThree)
{
    Assert.True(true);
}

Throws the following exception:

---- System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.

-------- System.ArgumentOutOfRangeException : Specified argument was out of the range of valid values. Parameter name: value

This question (almost word for word) was recently asked on the AutoFixture Github, but the supplied answer:

AutoData and InlineAutoData do not become aware of Moq when you just install the AutoFixture.AutoMoq package. Instead, you should create your own data attributes derived from the default ones, customize fixture with Moq support and use them

Doesn't make sense to me. Why should two mocks work but not three? How does creating my own data attribute help, and exactly how should I customise fixture with Moq support?

It's worth noting that I'm not using AutoMoq as I've never needed to in the past. I could just as easily new up the mocks myself in the test and I intend to as I need it working, but I'm curious as to why something that used to work just fine no longer does: Was I using it wrong all along and it just worked by happy chance?


Solution

  • Autofixture uses round-robin to assign default values therefore it fails on 3 mocks. This is an explanation on Autofixture issues page.

    The issue happens when AutoFixture tries to auto-assign properties to a newly created Mock object. The auto-generated DefaultValue property doesn't suits very well, so Moq fails. For the enum values AutoFixture uses the round-robin strategy, which explains why the case with 2 mocks works, while 3 mocks start to crash it.

    You can read the full comment here