【问题标题】:AutoFixture: mock methods don't return a frozen instanceAutoFixture:模拟方法不返回冻结的实例
【发布时间】:2014-08-22 02:06:34
【问题描述】:

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

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是通过构造函数初始化的接口字段。

我希望测试通过但它失败了,结果证明从 CreatePostProcessingActionFromJobResultXml 方法返回的 IPostProessingAction 实例与从 fixture.Freeze&lt;&gt; 返回的实例不同。

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

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

【问题讨论】:

  • postProcessingActionReader 的实现是什么样的?

标签: moq autofixture


【解决方案1】:

您需要Freeze IPostProcessingActionReader 组件。

以下测试将通过:

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

如果您将 AutoFixture declaratively 与 xUnit.net extension 一起使用,则可以进一步简化测试:

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

【讨论】:

  • 感谢您的详尽解答!我想知道是否有像 AutoFixture 这样的库,它会更进一步并自动在模拟上设置方法返回结果,这样我就不必做额外的返回值设置工作。
  • 不客气!目前,您可以尝试使用this answer 自动填充自动模拟实例的属性。
【解决方案2】:

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

换句话说,它会自动配置您的postProcessingActionReader 以返回冻结的postProcessingAction

只需改变这个:

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

到这里:

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

【讨论】:

    猜你喜欢
    • 2012-11-09
    • 1970-01-01
    • 1970-01-01
    • 2017-07-25
    • 2014-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多