1
Vote

AutoMoq customization should not intercept mocked object method return values

description

Here is a test case that should pass for both but fails on AutoMoq:
[TestClass]
public class Tests
{
    public class TestObject
    {
        public int Id { get; set; }
    }


    public interface IService
    {
        TestObject GetTestObject ();
    }


    [TestMethod]
    public void AutoMoq_InterfaceReturningReferenceObjects_ReturnsNull ()
    {
        // arrange
        var fixture = new Fixture ();
        fixture.Customize (new AutoMoqCustomization ());


        // act
        var result = fixture.Create<IService> ().GetTestObject ();


        // assert
        result.Should ().BeNull ();
    }


    [TestMethod]
    public void Moq_InterfaceReturningReferenceObjects_ReturnsNull ()
    {
        // arrange
        var mock = new Mock<IService> ();


        // act
        var result = mock.Object.GetTestObject ();


        // assert
        result.Should ().BeNull ();
    }
}

comments

ploeh wrote Feb 20, 2014 at 9:03 AM

This behaviour is expected, since AutoMoq uses DefaultValue.Mock. See here for more details: http://stackoverflow.com/a/18170070/126014

FuriCuri wrote Feb 20, 2014 at 9:39 AM

I see. Is there any way to force AutoMoq to behave like Mock itself (returning default value for a type - null in case of reference types)?

ploeh wrote Feb 20, 2014 at 10:17 AM

Not with a single line of code, but it should be possible. Here are some other articles on customizing AutoMoq to get you started:

http://blog.ploeh.dk/2013/04/05/how-to-configure-automoq-to-set-up-all-properties
http://blog.ploeh.dk/2013/04/08/how-to-automatically-populate-properties-with-automoq

FuriCuri wrote Feb 21, 2014 at 7:23 AM

I wish that was a bit more simple (like moving mock postprocessor configuration to optional constructor argument of AutoMoqCustomization).

Anyway, for those who struggle with this behaviour of Mock here is an alternative AutoMoqCustomization which revert default mock return values to DevalutValue.Empty:
public class AutoMoqWithNoDefaultValuesCustomization : ICustomization
{
    public void Customize (IFixture fixture)
    {
        fixture.Customizations.Add (new MockNoDefaultDefaultValuePostprocessor (new MockPostprocessor (new MethodInvoker (new MockConstructorQuery ()))));
        fixture.ResidueCollectors.Add (new MockRelay ());
    }
}


public class MockNoDefaultDefaultValuePostprocessor : ISpecimenBuilder
{
    private readonly ISpecimenBuilder builder;


    public MockNoDefaultDefaultValuePostprocessor (ISpecimenBuilder builder)
    {
        this.builder = builder;
    }


    public object Create (object request, ISpecimenContext context)
    {
        var request_mocked_type = GetMockedType (request as Type);
        if (request_mocked_type == null)
            return new NoSpecimen (request);

        var mock = this.builder.Create (request, context) as Mock;
        if (mock == null)
            return new NoSpecimen (request);

        if (GetMockedType (mock.GetType ()) != request_mocked_type)
            return new NoSpecimen (request);

        mock.DefaultValue = DefaultValue.Empty;

        return mock;
    }


    private static Type GetMockedType (Type type)
    {
        if (type == null || !type.IsGenericType)
            return null;

        if (!typeof (Mock<>).IsAssignableFrom (type.GetGenericTypeDefinition ()))
            return null;

        return type.GenericTypeArguments.Single ();
    }
}