Search code examples
c#moqautofixtureautomoq

Automatically return fixture values from mocked generic functions?


My tests use Moq and AutoFixture, and often they are very verbose because they have many mock Setup() calls to configure mocks to return values created by AutoFixture. To make the tests easier to read and maintain I am trying to use AutoMoqCustomization with the ConfigureMembers feature to avoid unnecessary Setup() calls.

Mostly this is working as expected, however I have some interfaces with generic functions (AutoMapper mostly) that the AutoMoqCustomization does not seem to handle. Instead of returning an instance of the type from AutoFixture I receive a mocked instance.

I can achieve the behavior that I want by including a Setup() call for the generic function, but my goal was to remove as many of these Setup calls as possible.

I have set up the example below to reproduce the problem (in practice I am using AutoFixture to inject an IMapper instance via the constructor of another object, and that object makes the call to the IMapper interface, but that is not necessary to see the problematic behavior).

What I expect is for the call to sut.Map<object>() to work like the call to sut.Map(), returning the instance of object frozen in the fixture. Instead in variable retB I see an instance of ObjectProxy.

Including the commented line in the example that sets up the return value for Map<object>() will cause the test to pass, but I would prefer to omit this call in the same way that I can omit the Setup() call for Map().

Are generic functions supposed to auto-configured? Am I setting it up incorrectly?

using AutoFixture;
using AutoFixture.AutoMoq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace UnitTestProject1
{
    public interface IMapper
    {
        object Map();
        object Map<T>();
    }

    [TestClass]
    public class Tests
    {
        [TestMethod]
        public void Test()
        {
            var f = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true });
            var model = f.Freeze<object>();
            var sut = f.Create<IMapper>();

            //Mock.Get(sut).Setup(x => x.Map<object>()).ReturnsUsingFixture(f);

            var retA = sut.Map();
            var retB = sut.Map<object>();

            Assert.AreEqual(model, retA);
            Assert.AreEqual(model, retB);        }
    }
}


Solution

  • Indeed, generic methods aren't currently supported by the AutoMoq customization in autofixture, due to a limitation of how it's written, but there's an issue/PR that would integrate it: https://github.com/AutoFixture/AutoFixture/issues/1139

    As far as I can tell, it's just not merged yet because it would pull in a higher Moq dependency version. It makes use of the relatively-recently introduced DefaultValueProvider property of Moq to delegate all the 'default value' duties to AutoFixture instead of having Moq recursively introduce mocked objects. Sounds like exactly what you want.

    From the issue, here's an example of what it would look like to use if you were to introduce a customization similar to the one that the pull request introduces:

    var fixture = new Fixture();
    fixture.Customize<string>(x => x.FromSeed(y => "asf"));
    var mock = new Mock<IInterfaceWithGenericMethod>
    {
        DefaultValueProvider = new AutoFixtureValueProvider(fixture)
    };
    
    Assert.Equal("asf", mock.Object.GenericMethod<string>());