Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoFixture: mock methods don't return a frozen instance

I'm trying to write this simple test:

var fixture = new Fixture().Customize(new AutoMoqCustomization());

var postProcessingAction = fixture.Freeze<Mock<IPostProcessingAction>>();
var postProcessor = fixture.Freeze<PostProcessor>();

postProcessor.Process("", "");

postProcessingAction.Verify(action => action.Do());

The Verify check fails.
The code for postProcessor.Process is

public void Process(string resultFilePath, string jobId)
{
    IPostProcessingAction postProcessingAction =
        postProcessingActionReader
            .CreatePostProcessingActionFromJobResultXml(resultFilePath);

    postProcessingAction.Do();
}

postProcessingActionReader is an interface field initialized through the constructor.

I'm expecting the test to pass but it fails, it turns out the instance of IPostProessingAction returned from the CreatePostProcessingActionFromJobResultXml method is not the same instance as returned from fixture.Freeze<>.

My expectation was that after freezing this Mock object it would inject the underlying mock of the IPostProcessingAction interface in every place its required as well as make all mock methods returning IPostProcessingAction return this same object.

Is my expectation about the return value of the mock methods incorrect? Is there a way to change this behavior so that mock methods return the same frozen instance?

like image 636
axk Avatar asked Feb 05 '13 13:02

axk


2 Answers

You need to Freeze the IPostProcessingActionReader component.

The following test will pass:

[Fact]
public void Test()
{
    var fixture = new Fixture()
        .Customize(new AutoMoqCustomization());

    var postProcessingActionMock = new Mock<IPostProcessingAction>();

    var postProcessingActionReaderMock = fixture
        .Freeze<Mock<IPostProcessingActionReader>>();

    postProcessingActionReaderMock
        .Setup(x => x.CreatePostProcessingActionFromJobResultXml(
            It.IsAny<string>()))
        .Returns(postProcessingActionMock.Object);

    var postProcessor = fixture.CreateAnonymous<PostProcessor>();
    postProcessor.Process("", "");

    postProcessingActionMock.Verify(action => action.Do());
}

Assuming that the types are defined as:

public interface IPostProcessingAction
{
    void Do();
}

public class PostProcessor
{
    private readonly IPostProcessingActionReader actionReader;

    public PostProcessor(IPostProcessingActionReader actionReader)
    {
        if (actionReader == null)
            throw new ArgumentNullException("actionReader");

        this.actionReader = actionReader;
    }

    public void Process(string resultFilePath, string jobId)
    {
        IPostProcessingAction postProcessingAction = this.actionReader
            .CreatePostProcessingActionFromJobResultXml(resultFilePath);

        postProcessingAction.Do();
    }
}

public interface IPostProcessingActionReader
{
    IPostProcessingAction CreatePostProcessingActionFromJobResultXml(
        string resultFilePath);
}

In case you use AutoFixture declaratively with the xUnit.net extension the test could be simplified even further:

[Theory, AutoMoqData]
public void Test(
    [Frozen]Mock<IPostProcessingActionReader> readerMock,
    Mock<IPostProcessingAction> postProcessingActionMock,
    PostProcessor postProcessor)
{
    readerMock
        .Setup(x => x.CreatePostProcessingActionFromJobResultXml(
            It.IsAny<string>()))
        .Returns(postProcessingActionMock.Object);

    postProcessor.Process("", "");

    postProcessingActionMock.Verify(action => action.Do());
}

The AutoMoqDataAttribute is defined as:

internal class AutoMoqDataAttribute : AutoDataAttribute
{
    internal AutoMoqDataAttribute()
        : base(new Fixture().Customize(new AutoMoqCustomization()))
    {
    }
}
like image 157
Nikos Baxevanis Avatar answered Nov 01 '22 06:11

Nikos Baxevanis


As of 3.20.0, you can use AutoConfiguredMoqCustomization. This will automatically configure all mocks so that their members' return values are generated by AutoFixture.

In other words, it will auto-configure your postProcessingActionReader to return the frozen postProcessingAction.

Just change this:

var fixture = new Fixture().Customize(new AutoMoqCustomization());

to this:

var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());
like image 21
dcastro Avatar answered Nov 01 '22 06:11

dcastro