3

我正在创建单元测试,它需要逐个成员比较相同类型的两个对象。我决定使用 SemanticComparison 库来处理此任务,而无需编写自定义比较器代码。它在比较平面对象时非常有效,当对象包含嵌套对象时,也需要按成员进行比较时会出现问题。

public class Outer
{
    public string Name { get; set; }
    public Inner Inner { get; set; }
}

public class Inner
{
    public string Name { get; set; }
    public string Value { get; set; }
}

public class Service
{
    public Outer Method()
    {
        return new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value1"
            }
        };
    }
}

这不起作用,因为 Inner 对象是通过引用而不是按成员进行比较的:

    [Test]
    public void SimpleTest1()
    {

        // setup
        var expectedLikeness = new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value1"
            }
        }.AsSource().OfLikeness<Outer>();

        var sut = new Service();
        // exercise sut
        var actual = sut.Method();
        // verify
        expectedLikeness.ShouldEqual(actual);
    }

为了使它工作,我必须创建嵌套对象的代理,以便它覆盖默认的 equals 实现。

    [Test]
    public void SimpleTest2()
    {

        // setup
        var expectedLikeness = new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value1"
            }.AsSource().OfLikeness<Inner>().CreateProxy()
        }.AsSource().OfLikeness<Outer>();

        var sut = new Service();
        // exercise sut
        var actual = sut.Method();
        // verify
        expectedLikeness.ShouldEqual(actual);
    }

好吧,它可以正常工作,但是想象一下,经过一些服务代码重构后,我们引入了导致 Inner 类的 value 属性与预期值不同的 bug。SemanticComparison 的一个很酷的特性是它可以记录导致不等式的成员的名称。但是,在这种情况下,它只会返回不匹配的“Inner”,而不是 Inner 类中特定属性的名称。

我错过了什么吗?是否可以将其配置为能够返回实际的不匹配成员。

对于本例中的简单数据结构而言,这显然不是问题,但对于测试现实生活中的代码可能会带来不便。

4

2 回答 2

3

由于没有人回答,我将提供我自己的答案。

因此,除非您编写一些额外的代码,否则您似乎无法做到 OOTB。我已经将代码包装在一组扩展方法中。这些方法允许您指定应该使用内部相似性而不是通过引用来比较哪些内部属性/集合属性。您不需要手动创建任何代理,一切都由这些扩展在内部处理。并且所有内部比较的结果都被记录下来,因此您可以准确地看到哪些成员具有无效值。

这是使用“WithInnerLikeness”扩展方法的问题的测试。

    [Test]
    public void ServiceTest3()
    {
        // setup
        var expected = new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value2"
            }
        };

        var expectedLikeness = expected.AsSource().OfLikeness<Outer>()
            .WithInnerLikeness(d => d.Inner, s => s.Inner)
            ;

        var sut = new Service();
        // exercise sut
        var actual = sut.Method();
        // verify
        expectedLikeness.ShouldEqual(actual);
    }

您可以看到内部对象的值属性不匹配,因此测试应该失败。它失败并在输出中显示以下消息:

Comparing inner properties using likeness. Source: s => s.Inner Destination: d => d.Inner.
The source and destination values are not equal. Details: The provided value ClassLibrary1.Inner did not match the expected value ClassLibrary1.Inner. The following members did not match:
- Value.

Ploeh.SemanticComparison.LikenessException : The provided value ClassLibrary1.Outer did not match the expected value ClassLibrary1.Outer. The following members did not match:
- Inner.

您可以在 github 上找到源代码和更多示例。

https://github.com/jmansar/SemanticComparisonExtensions

于 2014-07-06T15:26:52.310 回答
0

这是一个真正的耻辱,它不支持开箱即用。

作为替代方案,您可以尝试Fluent Assertions,请参阅对象图比较

actual.Should().BeEquivalentTo(expected);

在比较、成员排除等方面有很多灵活性,并且开箱即用地支持嵌套对象属性。

希望这可以帮助!

于 2020-05-22T05:46:11.113 回答