6

我正在尝试编写这个简单的测试:

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());

Verify检查失败。
postProcessor.Process 的代码是

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

    postProcessingAction.Do();
}

postProcessingActionReader是通过构造函数初始化的接口字段。

我期待测试通过,但它失败了,结果证明IPostProessingActionCreatePostProcessingActionFromJobResultXml方法返回的实例与从fixture.Freeze<>.

我的期望是,在冻结这个 Mock 对象后,它将IPostProcessingAction在所需的每个地方注入接口的底层模拟,并使所有返回的模拟方法返回IPostProcessingAction相同的对象。

我对模拟方法的返回值的期望不正确吗?有没有办法改变这种行为,以便模拟方法返回相同的冻结实例?

4

2 回答 2

5

您需要FreezeIPostProcessingActionReader组件。

以下测试将通过:

[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());
}

假设类型定义为:

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);
}

如果您通过xUnit.net扩展以声明方式使用 AutoFixture,则可以进一步简化测试:

[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());
}

AutoMoqDataAttribute定义为:

internal class AutoMoqDataAttribute : AutoDataAttribute
{
    internal AutoMoqDataAttribute()
        : base(new Fixture().Customize(new AutoMoqCustomization()))
    {
    }
}
于 2013-02-05T14:26:54.803 回答
4

从 3.20.0 开始,您可以使用AutoConfiguredMoqCustomization. 这将自动配置所有模拟,以便其成员的返回值由 AutoFixture 生成。

换句话说,它会自动配置你postProcessingActionReader返回 freeze postProcessingAction

只需更改此:

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

对此:

var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());
于 2014-08-21T18:06:34.953 回答