将[AutoFixture] SemanticComparison OfLikeness应用于序列/集合/数组/ IEnumerable

Tom*_*ise 12 .net collections unit-testing autofixture semantic-comparison

我们编写了一个如下所示的测试.此测试要求我们EqualCodeTableItem-class 创建了en -overload :

ICollection<CodeTableItem> expectedValutaList = new List<CodeTableItem>();
expectedValutaList.Add(new CodeTableItem("DKK", "DKK"));
expectedValutaList.Add(new CodeTableItem("EUR", "EUR"));
RepoDac target = new RepoDac(); 

var actual = target.GetValutaKd();

CollectionAssert.AreEqual(expectedValutaList.ToList(),actual.ToList());
Run Code Online (Sandbox Code Playgroud)

测试工作正常,但是对Equality函数有一个不幸的依赖,这意味着如果我CodeTableItem用一个字段扩展-class,并忘记扩展Equals-function,单元测试仍然会运行绿色,尽管我们不测试所有字段.我们希望避免这种Equality污染(参见测试特定平等),这种污染只是为了符合测试而编写的.

我们尝试过使用OfLikeness,并以这种方式重写了测试:

ICollection<CodeTableItem> expectedValutaList = new List<CodeTableItem>();
expectedValutaList.Add(new CodeTableItem("DKK", "DKK"));
expectedValutaList.Add(new CodeTableItem("EUR", "EUR"));
var expectedValutaListWithLikeness = 
          expectedValutaList.AsSource().OfLikeness<List<CodeTableItem>>();

RepoDac target = new RepoDac(); 
ICollection<CodeTableItem> actual;

actual = target.GetValutaKd();

expectedValutaListWithLikeness.ShouldEqual(actual.ToList());
Run Code Online (Sandbox Code Playgroud)

但测试失败是因为Capacity不相等.我编写了多次运行反射的代码,并且通常最终实现了忽略字段的重载.有没有办法用OfLikeness或忽略某些字段ShouldEqual?或者还有其他方法可以解决这个问题吗?

Mar*_*ann 12

为什么你不想这样做

我不认为从任何List<T>事情中创造一种与你想要它做的相似.据我了解,您想比较两个列表的内容.这与比较两个列表不一样......

考虑Likeness的作用:它比较属性值.有什么属性List<T>

他们是

  • 容量
  • 计数

正如Nikos Baxevanis在他的回答中指出的那样,你可以使用Without方法忽略Capacity属性的值,但这意味着只剩下Count属性.

换句话说,如果你这样做,这个:

expectedValutaListWithLikeness.ShouldEqual(actual.ToList());
Run Code Online (Sandbox Code Playgroud)

在功能上等同于:

Assert.AreEqual(expected.Count, actual.Count)
Run Code Online (Sandbox Code Playgroud)

换句话说,列表可能具有完全不同的数据,但如果只有每个列表具有相同数量的元素,则测试仍将通过.这可能不是你想要的......

你应该做什么

您可以使用"相似性"将每个元素相互比较.这样的事情应该有效:

var expectedValutaList = new List<CodeTableItem>();
expectedValutaList.Add(new CodeTableItem("DKK", "DKK"));
expectedValutaList.Add(new CodeTableItem("EUR", "EUR"));

var expectedValutaListWithLikeness = from cti in expectedValutaList
                                     select cti
                                         .AsSource()
                                         .OfLikeness<CodeTableItem>();

var target = new RepoDac(); 

var actual = target.GetValutaKd();

Assert.IsTrue(expectedValutaListWithLikeness.Cast<object>().SequenceEqual(
    actual.Cast<object>()));
Run Code Online (Sandbox Code Playgroud)

您也可以使用CollectionAssert作为断言,但是自从我上次使用MSTest以来已经这么多年了,我不记得那个方法的怪癖......


Nik*_*nis 8

只需添加.Without(x => x.Capacity)和Likeness实例将Capacity在比较值时忽略该属性.

var expectedValutaListWithLikeness = 
      expectedValutaList.AsSource().OfLikeness<List<CodeTableItem>>()
      .Without(x => x.Capacity);
Run Code Online (Sandbox Code Playgroud)

更新:

正如Mark Seemann在他的回答中指出的那样,你可能想要的是将每个元素相互比较.这是一种略微不同的方式,允许您执行非常灵活的比较.

假设RepoDac类返回类似于:

public class RepoDac
{
    public ICollection<CodeTableItem> GetValutaKd()
    {
        return new[]
        {
            new CodeTableItem("DKK", "DKK"),
            new CodeTableItem("EUR", "EUR")
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

对于每个实例,expectedValutaList您可以创建一个使用Likeness覆盖Equals的动态代理:

var object1 = new CodeTableItem("DKK", "DKK1")
    .AsSource().OfLikeness<CodeTableItem>()
    .Without(x => x.Property2)
    .CreateProxy();

var object2 = new CodeTableItem("EUR2", "EUR")
    .AsSource().OfLikeness<CodeTableItem>()
    .Without(x => x.Property1)
    .CreateProxy();
Run Code Online (Sandbox Code Playgroud)

注意object1和object2如何具有不同的动态生成的Equals.(第一个忽略Property2而第二个忽略Property1.)

以下测试通过:

var expected = new List<CodeTableItem>();
expected.Add(object1);
expected.Add(object2);

var target = new RepoDac();
var actual = target.GetValutaKd();

Assert.IsTrue(expected.SequenceEqual(actual));
Run Code Online (Sandbox Code Playgroud)

注意:

需要从expected包含动态生成的代理(覆盖Equals)的实例开始.

您可以在此处找到有关此功能的更多信息.