【问题标题】:Trouble using Autofixture's CreateProxy to use Likeness, SemanticComparison features使用 Autofixture 的 CreateProxy 来使用 Likeness、SemanticComparison 功能时遇到问题
【发布时间】:2013-03-11 15:11:00
【问题描述】:

earlier question 中,我询问了Autofixture 的CreateProxy method,发现potential bug

我不认为这个失败的测试是因为这个,而是我对 Likeness.Without(...).CreateProxy() 语法如何工作的持续困惑。考虑以下失败的测试,其中我通过创建对象的新实例使original test稍微复杂,考虑到它的创建是SUT

[Fact]
public void Equality_Behaves_As_Expected()
{
    // arrange: intent -> use the fixture-created Band as Object Mother
    var template = new Fixture().Create<Band>();

    // act: intent -> instantiated Band *is* the SUT
    var createdBand = new Band {Brass = template.Brass,
                                Strings = template.Brass};

    //   intent -> specify that .Brass should not be considered in comparison 
    var likeness = template.AsSource().OfLikeness<Band>().
        Without(x => x.Brass).CreateProxy(); // Ignore .Brass property

    // per [https://stackoverflow.com/a/15476108/533958] explicity assign
    // properties to likeness
    likeness.Strings = template.Strings;
    likeness.Brass = "foo"; // should be ignored

    // assert: intent -> check equality between created Band & template Band
    //         to include all members not excluded in likeness definition
    likeness.Should().Be(createdBand);          // Fails
    likeness.ShouldBeEquivalentTo(createdBand); // Fails
    Assert.True(likeness.Equals(createdBand));  // Fails
}

这是乐队:

public class Band
{
    public string Strings { get; set; }
    public string Brass { get; set; }
}

我的earlier question 不够复杂,无法帮助我理解LikenessSource 通常应该是什么。

源应该是SUT 的输出,在这种情况下,它将与 AutoFixture 创建的 模板 实例进行比较?

或者源应该是 AutoFixture 创建的 模板 实例,在这种情况下,它将与 SUT 的输出进行比较?

编辑:更正了测试中的一个错误

我意识到我错误地将template.Brass 属性分配给两个 Brass Band 实例的Strings 属性。更新后的测试反映了var createdBand = new Band {Brass = template.Brass, Strings = template.Strings} 的更正,所有六个断言现在都通过了。

[Fact]
public void Equality_Behaves_As_Expected()
{
    // arrange: intent -> use the fixture-created Band as Object Mother
    var template = new Fixture().Create<Band>();

    // act: intent -> instantiated Band *is* the SUT
    var createdBand = new Band {Brass = template.Brass, Strings = template.Strings};

    // likeness of created
    var createdLikeness = createdBand.AsSource().OfLikeness<Band>().
        Without(x => x.Brass).CreateProxy(); // .Brass should not be considered in comparison 

    // https://stackoverflow.com/a/15476108/533958 (explicity assign properties to likeness)
    createdLikeness.Strings = createdBand.Strings;
    createdLikeness.Brass = "foo"; // should be ignored

    // likeness of template
    var templateLikeness = template.AsSource().OfLikeness<Band>()
        .Without(x => x.Brass)
        .CreateProxy();
    templateLikeness.Strings = template.Strings;
    templateLikeness.Brass = "foo";

    // assert: intent -> compare created Band to template Band
    createdLikeness.Should().Be(template);
    createdLikeness.ShouldBeEquivalentTo(template);
    Assert.True(createdLikeness.Equals(template));

    templateLikeness.Should().Be(createdBand);
    templateLikeness.ShouldBeEquivalentTo(createdBand);
    Assert.True(templateLikeness.Equals(createdBand));
}

【问题讨论】:

  • @NikosBaxevanis 感谢您为此所做的工作!在那之前,我已经完成了您在对我之前的问题的回答中提出的建议,即明确地将属性值分配给我将要检查相等性的实例中我期望的值,但排除的任何属性除外使用 .Without(...) 语法的相似性。我的那部分对吗?
  • @Lumiris 是的,没错。
  • 从 3.0.4 及更高版本开始,值会自动复制到代理实例(这意味着,createdLikeness.Strings = createdBand.Strings; 将自动发生)

标签: unit-testing autofixture stub-data-generation semantic-comparison


【解决方案1】:

你的意思是:

likeness.Should().BeAssignableTo<Band>(); // Returns true.

在提供的示例中,从Likeness 生成的代理是从Band 派生的类型,使用语义比较算法覆盖Equals

使用反射是:

createdBand.GetType().IsAssignableFrom(likeness.GetType()) // Returns true.

更新

createBandtemplate 实例不受CreateProxy 方法的影响。为什么他们应该这样做?

使用 Likeness CreateProxy,您基本上可以创建一个 Custom Equality Assertion,它允许您执行以下操作:

Assert.True(likeness.Equals(createdBand)); // Passed. 

没有它,原来的平等断言会失败:

Assert.True(template.Equals(createdBand)); // Failed.

但是,以下操作也会失败:

Assert.True(likeness.Equals(template));

它失败了,因为 Strings 值是来自 createdBand 实例的值。

这种行为是意料之中的,您可以直接使用Likeness 进行验证:

 createdBand.AsSource().OfLikeness<Band>()
     .Without(x => x.Brass).ShouldEqual(template);

输出:

 The provided value `Band` did not match the expected value `Band`. The following members did not match:
      - Strings.

【讨论】:

  • 不就是比较类型吗?我想比较相似度(从模板创建)与 createdBand(从 SUT 创建)是否相等(除了那些在相似度创建中特别排除的成员之外的所有成员)。我有足够的信心,它们将属于相同类型或可分配给我不想明确验证的相同类型。我会尝试更新问题以更清楚地说明这一点。
  • @Lumirris 在更新后的测试中,您必须将 Likeness 代理(目标)与 模板 实例(源)进行比较。
  • 如果我更新到 likeness.Should().Be(template),测试通过,但它不检查 SUT 输出 (createdBand)。但是如果createdBand 被用作相似性来源(var likeness = createdBand.AsSource().OfLikeness&lt;Band&gt;().Without(x =&gt; x.Brass).CreateProxy()likeness.Strings = createdBand.Strings),那么 SUT 的输出会通过相似性被引用,并且测试再次失败。我认为肖像必须完全由createdBand 或完全由template 组成,无论哪种方式测试都失败了。对不起,如果我没有得到明显的东西 - 我真的很想得到它。
  • @Lumirris AFAICT the test passed..
  • @Lumirris CreateProxy 生成一个派生自 TDestination 的类型,覆盖 Equals.. 可能很快就会发布一篇博文 is on the way
猜你喜欢
  • 1970-01-01
  • 2020-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-09
  • 2014-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多