我有一个NUnit单元测试,我有两个不同类型的集合,我想断言是等价的。
class A { public int x; }
class B { public string y; }
[Test]
public void MyUnitTest()
{
var a = GetABunchOfAs(); // returns IEnumerable<A>
var b = GetABunchOfBs(); // returns IEnumerable<B>
Assert.IsPrettySimilar(a, b, (argA, argB) => argA.ToString() == argB);
}
其中Assert.IsPrettySimilar
的定义如此
public static void IsPrettySimilar<T1, T2>(
IEnumerable<T1> left,
IEnumerable<T2> right,
Func<T1, T2, bool> predicate)
{
using (var leftEnumerator = left.GetEnumerator())
using (var rightEnumerator = right.GetEnumerator())
{
while (true)
{
var leftMoved = leftEnumerator.MoveNext();
if (leftMoved != rightEnumerator.MoveNext())
{
Assert.Fail("Enumerators not of equal size");
}
if (!leftMoved)
{
break;
}
var isMatch = predicate(leftEnumerator.Current,
rightEnumerator.Current);
Assert.IsTrue(isMatch);
}
}
}
我的问题是,在NUnit中使用现有方法执行上述操作是否有更惯用的方法?我已经查看了CollectionAssert
,并没有什么能与我想做的相提并论。
在这种情况下,我对“等效”的描述是:
1)收藏品必须大小相同
2)集合必须具有相同的逻辑顺序
3)必须使用一些谓词来确定匹配项之间的等价性。
答案 0 :(得分:1)
我知道你调查了CollectionAssert
,然而,我发现这样的策略在我自己的测试中非常有用。
在对象上覆盖ToString和Equals会使此测试通过。
[TestFixture]
public class Class1
{
[Test]
public void MyUnitTest()
{
var a = GetABunchOfAs(); // returns IEnumerable<A>
var b = GetABunchOfBs(); // returns IEnumerable<B>
CollectionAssert.AreEqual(a, b.OrderBy(x => x.y));
}
public List<A> GetABunchOfAs()
{
return new List<A>
{
new A() {x = 1},
new A() {x = 2},
new A() {x = 3},
new A() {x = 4}
};
}
public List<B> GetABunchOfBs()
{
return new List<B>
{
new B() {y = "4"},
new B() {y = "1"},
new B() {y = "2"},
new B() {y = "3"},
};
}
}
public class A
{
public int x;
public override bool Equals(object obj)
{
return obj.ToString().Equals(x.ToString());
}
public override string ToString()
{
return x.ToString();
}
}
public class B
{
public string y;
public override string ToString()
{
return y;
}
public override bool Equals(object obj)
{
return obj.ToString().Equals(y);
}
}
我故意将GetABunchOfBs排除在外,但测试仍然通过。
答案 1 :(得分:1)
让我们考虑一下您要测试的内容。您没有尝试测试第一个序列中的对象与第二个序列中的对象相同。它们可能非常不同。所以,类似这个词在这里很模糊。你真正想在这里测试的是,第一序列的某些投影等于第二序列的其他投影。 NUnit已经拥有了这样的功能:
CollectionAssert.AreEqual(bunchOfAs.Select(a => a.ToString()),
bunchOfBs.Select(b => b));
因此,您要投射两个序列以获取特定数据,然后您可以为这两个投影指定漂亮的名称,这将使您的测试对其他人可读。你在这里有一些隐藏的业务逻辑,在代码中没有解释 - 你不能解释为什么你做出这样的预测。因此,投影结果的好名称将解释您的意图。 E.g:
var expectedNames = employees.Select(u => u.Login);
var actualNames = customers.Select(c => c.Name);
CollectionAssert.AreEqual(expectedNames, actualNames);
对我而言,这比
更清洁 Assert.IsPrettySimilar(employees, customers, (e, c) => u.Login == c.Name);
答案 2 :(得分:0)
看起来谢尔盖的答案是我正在寻找的答案(这是为了看看NUnit是否已经拥有了我想要的设施)。但是,这是我最终得到的解决方案,它更接近我想要的实现。
public static class EnumerableAssert
{
public static void AreEquivilent<TExpected, TActual>(IEnumerable<TExpected> expected, IEnumerable<TActual> actual, Func<TExpected, TActual, bool> predicate)
{
if (ReferenceEquals(expected, actual))
{
return;
}
using (var expectedEnumerator = expected.GetEnumerator())
using (var actualEnumerator = actual.GetEnumerator())
{
while (true)
{
var expectedMoved = expectedEnumerator.MoveNext();
if (expectedMoved != actualEnumerator.MoveNext())
{
Assert.Fail("Expected and Actual collections are of different size");
}
if (!expectedMoved)
{
return;
}
Assert.IsTrue(predicate(expectedEnumerator.Current, actualEnumerator.Current));
}
}
}
}