POAL violation on Mock construction using AutoMoq

Dec 23, 2011 at 1:18 PM
Edited Dec 23, 2011 at 1:21 PM

1.

public abstract class AbstractTypeWithNonDefaultConstructor<T>
{
    private readonly T property;

    protected AbstractTypeWithNonDefaultConstructor(T value)
    {
        if (value == null)
        {
            throw new ArgumentNullException("value");
        }

        this.property = value;
    }

    public T Property
    {
        get { return this.property; }
    }
}



[Fact]
public void Test()
{
    //Case1. using Moq
    Mock<AbstractTypeWithNonDefaultConstructor<int>> mockFromMoq 
        = new Mock<AbstractTypeWithNonDefaultConstructor<int>>();
    Assert.Throws<ArgumentException>(() => mockFromMoq.Object);

    //using AutoMoq
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    //Case2. CreateAnonymous
    var mockFromCreateAnonymous = 
        fixture.CreateAnonymous<Mock<AbstractTypeWithNonDefaultConstructor<int>>>();
    Assert.NotNull(mockFromCreateAnonymous.Object);
    //Case3. Buld
    var mockFromBuild = 
        fixture.Freeze<Mock<AbstractTypeWithNonDefaultConstructor<int>>>(
        x => x.OmitAutoProperties());
    Assert.Throws<ArgumentException>(() => mockFromBuild.Object);
}

 

As you can see above, these three assertions are passed successfully, but at the case 2, if  a user have used Moq before and is new on AutoMoq, he/she would be astonished because throwing Exception is expected. With this reason, I would like to suggest that the cast 2 also throw the exception and AutoMoq supports only constructing Mock of parameterless mocked type, where the mocked type means generic type of mock.

To get the result as the case2, we can use the new modified AbstractTypeWithNonDefaultConstructor with using the private default construction and setting up of the mock class as below.

 

 

public abstract class AbstractTypeWithNonDefaultConstructor<T>
{
    private readonly T property;

    private AbstractTypeWithNonDefaultConstructor(){}

    protected AbstractTypeWithNonDefaultConstructor(T value)
    {
        if (value == null)
        {
            throw new ArgumentNullException("value");
        }

        this.property = value;
    }

    public virtual T Property
    {
        get { return this.property; }
    }
}

Mock<AbstractTypeWithNonDefaultConstructor<int>> mockFromMoq
    = new Mock<AbstractTypeWithNonDefaultConstructor<int>>();
mockFromMoq.SetupGet(x => x.Property).Returns(1);

 

2. The mock object initialized from Moq has "false" as CallBase and "Empty" as DefaultValue, but in the case of AutoMoq, CallBase and DefaultValue have the other value of them. It also be considered as POLA violation by Moq users. The workaround of it I thought is to give users the options about it, which is to pass the values of CallBase and DefaultValue to the constructor of AutoMoqCustomization.

Coordinator
Dec 28, 2011 at 10:09 AM

This is essentially the same problem as discussed here.

However, I don't agree that case 2 is a POLA violation, since the whole point of Auto-mocking is to enable Auto-wiring of the mock instances. This is exactly what happens in case 2, where an anonymous integer is being automatically supplied to the protected constructor. This is very much by design.

Case 3, on the other hand, is surprising - I knew that Freeze overload would come back to bite me some day :/ Basically, this Freeze method is just an extension method around the Build method, so it's the same issue at play here as in the previously mentioned discussion.