Autofixture: 冻结模拟不会覆盖注入的实例

创建于 2018-07-31  ·  1评论  ·  资料来源: AutoFixture/AutoFixture

当前行为

当注入两个具体实例时,第二个实例会覆盖第一个实例。

当注入一个具体实例,然后是一个模拟实例时,第二个实例不会覆盖第一个实例。

这使得执行一些使用模拟的测试和一些使用实现的测试(使用测试类构造函数在测试之间共享夹具)的想法相当笨拙。

预期行为

当注入两个具体实例时,第二个实例会覆盖第一个实例。

当注入一个具体实例,然后是一个模拟实例时,第二个实例会覆盖第一个实例。

预期行为示例

```C#
使用 System.Collections.Generic;
使用 AutoFixture;
使用 AutoFixture.AutoMoq;
使用最小起订量;
使用 Xunit;

命名空间 SomeNamespace
{
公共类 AutoFixtureTests
{
[事实]
// 通过
public void Should_OverridePreviouslyInjectedString()
{
const string test1 = "test1";
const string test2 = "test2";

        var fixture = new Fixture();

        fixture.Inject(test1);
        fixture.Inject(test2);

        Assert.Equal(fixture.Create<string>(), test2);
    }

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

        var sut1 = new List<int>();

        fixture.Inject<IList<int>>(sut1);
        fixture.Freeze<Mock<IList<int>>>();

        var sut2 = fixture.Create<IList<int>>();

        Assert.NotSame(sut1, sut2);
    }
}

}
``

question

最有用的评论

嗨@charles-salmon,

感谢您抽出时间报告此事。

您观察到的行为是_by design_。 请允许我解释一下。 🙂

如果你看一下执行的的Freeze<T>方法:

var value = fixture.Create<T>();
fixture.Inject(value);
return value;

你会看到它所做的只是创建一个T的样本并将它注入到夹具中。 实际上, Freeze方法是作为此操作的便捷快捷方式出现的。 正如@ploeh在 2010 年介绍 Freeze 方法的帖子中所写:

事实证明,我们如此频繁地使用这种编码习惯用法,以至于我们决定将其封装在一种方便的方法中。 经过一番讨论,我们得出了 Freeze 这个名字,因为我们基本上冻结了夹具中的一个匿名变量,绕过了创建新实例的默认算法。

鉴于此,冻结与注入实例相同的类型T产生相同的实例也就不足为奇了。

现在,要解决您的问题:

这使得执行一些使用模拟的测试和一些使用实现的测试(使用测试类构造函数在测试之间共享夹具)的想法相当笨拙。

鉴于夹具代表测试运行的 _context_,您当然可以_让多个测试共享同一个夹具; 然而,这是以混合多个(可能是相互冲突的)问题为代价的。

xUnit Patterns 一书很好地总结了它

Shared Fixture的最大问题是它可能导致测试之间的“冲突”,这可能导致Erratic Tests ,因为测试可能取决于其他测试的结果。 另一个问题是,设计用于多个测试的夹具肯定比单个测试所需的最小夹具复杂得多。

当一个测试期望T类型的对象是一个特定实例,而另一个测试期望T是一个假对象时,就会发生这种“冲突”。

由于我想不出一个测试场景,其中相同类型的T既是模拟 _ 又是具体实例(尽管我很高兴被证明是错误的),我建议你有这些测试使用不同的装置,每个装置都被配置为服务于它们的特定场景。

>所有评论

嗨@charles-salmon,

感谢您抽出时间报告此事。

您观察到的行为是_by design_。 请允许我解释一下。 🙂

如果你看一下执行的的Freeze<T>方法:

var value = fixture.Create<T>();
fixture.Inject(value);
return value;

你会看到它所做的只是创建一个T的样本并将它注入到夹具中。 实际上, Freeze方法是作为此操作的便捷快捷方式出现的。 正如@ploeh在 2010 年介绍 Freeze 方法的帖子中所写:

事实证明,我们如此频繁地使用这种编码习惯用法,以至于我们决定将其封装在一种方便的方法中。 经过一番讨论,我们得出了 Freeze 这个名字,因为我们基本上冻结了夹具中的一个匿名变量,绕过了创建新实例的默认算法。

鉴于此,冻结与注入实例相同的类型T产生相同的实例也就不足为奇了。

现在,要解决您的问题:

这使得执行一些使用模拟的测试和一些使用实现的测试(使用测试类构造函数在测试之间共享夹具)的想法相当笨拙。

鉴于夹具代表测试运行的 _context_,您当然可以_让多个测试共享同一个夹具; 然而,这是以混合多个(可能是相互冲突的)问题为代价的。

xUnit Patterns 一书很好地总结了它

Shared Fixture的最大问题是它可能导致测试之间的“冲突”,这可能导致Erratic Tests ,因为测试可能取决于其他测试的结果。 另一个问题是,设计用于多个测试的夹具肯定比单个测试所需的最小夹具复杂得多。

当一个测试期望T类型的对象是一个特定实例,而另一个测试期望T是一个假对象时,就会发生这种“冲突”。

由于我想不出一个测试场景,其中相同类型的T既是模拟 _ 又是具体实例(尽管我很高兴被证明是错误的),我建议你有这些测试使用不同的装置,每个装置都被配置为服务于它们的特定场景。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

JoshKeegan picture JoshKeegan  ·  6评论

josh-degraw picture josh-degraw  ·  4评论

ploeh picture ploeh  ·  3评论

ploeh picture ploeh  ·  7评论

Accc99 picture Accc99  ·  4评论