我想断言,两个列表中的元素包含了我所料,喜欢的东西值:
var foundCollection = fooManager.LoadFoo();
var expectedCollection = new List<Foo>()
{
new Foo() { Bar = "a", Bar2 = "b" },
new Foo() { Bar = "c", Bar2 = "d" }
};
//assert: I use AreEquivalent since the order does not matter
CollectionAssert.AreEquivalent(expectedCollection, foundCollection);
但是上面的代码将无法正常工作(我猜是因为.Equals()不具有相同值对不同的对象返回true)。 在我的测试中,我只关心公共属性值,对象不是是否相等。 我能做些什么让我的说法对吗?
Answer 1:
返工ANSWER
有一个CollectionAssert.AreEqual(IEnumerable, IEnumerable, IComparer)
过载断言两个集合包含以相同的顺序相同的对象,使用IComparer
实施检查对象等价。
在上述情况下,顺序并不重要。 但是,要充分也处理这种情况有两个集合的多条等价物的情况下,有必要第一顺序中的每个集合中的对象,并使用一个接一个比较,以确保也就相当于对象的数量是相同的在两个集合。
Enumerable.OrderBy
提供过载,其采用IComparer<T>
参数。 为了确保两个集合以相同的顺序进行排序,它是或多或少要求该类型识别属性的实现IComparable
。 下面是同时实现一个比较器类的一个例子IComparer
和IComparer<Foo>
接口,并且其中,假设Bar
订货时优先:
public class FooComparer : IComparer, IComparer<Foo>
{
public int Compare(object x, object y)
{
var lhs = x as Foo;
var rhs = y as Foo;
if (lhs == null || rhs == null) throw new InvalidOperationException();
return Compare(lhs, rhs);
}
public int Compare(Foo x, Foo y)
{
int temp;
return (temp = x.Bar.CompareTo(y.Bar)) != 0 ? temp : x.Bar2.CompareTo(y.Bar2);
}
}
断言,在两个集合的对象是相同的,并配备人数相等(但不一定相同的顺序开始),以下行应该做的伎俩:
var comparer = new FooComparer();
CollectionAssert.AreEqual(
expectedCollection.OrderBy(foo => foo, comparer),
foundCollection.OrderBy(foo => foo, comparer), comparer);
Answer 2:
不,NUnit的有没有这样的机制,目前的状态。 你必须推出自己的断言逻辑。 作为单独的方法,或利用Has.All.Matches
:
Assert.That(found, Has.All.Matches<Foo>(f => IsInExpected(f, expected)));
private bool IsInExpected(Foo item, IEnumerable<Foo> expected)
{
var matchedItem = expected.FirstOrDefault(f =>
f.Bar1 == item.Bar1 &&
f.Bar2 == item.Bar2 &&
f.Bar3 == item.Bar3
);
return matchedItem != null;
}
当然,这假设你知道所有相关的属性前期(否则, IsInExpected
将不得不求助于反射)和元素的顺序是不相关的。
(和你的假设是正确的,NUnit的的收集断言的类型使用默认comparers,这在用户定义的人的大多数情况下,将对象ReferenceEquals
)
Answer 3:
使用Has.All.Matches()都非常好, 找到的收集比较预期的集合。 然而,这是没有必要定义由Has.All.Matches()作为一个单独的函数所使用的谓词。 对于相对简单的比较,谓词可以被包括作为这样lambda表达式的一部分。
Assert.That(found, Has.All.Matches<Foo>(f =>
expected.Any(e =>
f.Bar1 == e.Bar1 &&
f.Bar2 == e.Bar2 &&
f.Bar3= = e.Bar3)));
现在,虽然这种说法将确保发现集合中的每个条目也存在预期的收集,并不能证明相反的,即预期的集合中每个项目包含在发现收藏。 所以,当重要的是要知道, 发现和预期包含语义等价(即,它们含有相同的语义等价项),我们必须添加额外的断言。
最简单的选择是添加以下内容。
Assert.AreEqual(found.Count() == expected.Count());
对于那些谁喜欢一个更大的锤子,以下声明可被替代。
Assert.That(expected, Has.All.Matches<Foo>(e =>
found.Any(f =>
e.Bar1 == f.Bar1 &&
e.Bar2 == f.Bar2 &&
e.Bar3= = f.Bar3)));
通过结合使用上述第一断言与任一第二(优选的)或第三断言,我们现在已经证明,这两个集合是语义上是相同的。
Answer 4:
您是否尝试过像成才这样?
Assert.That(foundCollection, Is.EquivalentTo(expectedCollection))
Answer 5:
要在复杂的类型,你需要实现IComaprable执行equivilance操作。
http://support.microsoft.com/kb/320727
另外,您可以使用递归的反射,这是不太理想的。
Answer 6:
一种选择是编写自定义约束进行比较的品种。 下面是关于这个问题的好文章: http://www.davidarno.org/2012/07/25/improving-nunit-custom-constraints-with-syntax-helpers/
Answer 7:
我有一个类似的问题。 清单贡献者,其中包含“提意见”和其他脂肪酶...我想所有的意见,并从中导出的创造者,但我只OFC以独特的创造者感兴趣。 如果有人创建了50点意见,我只希望她的名字出现一次。 所以我写了一个测试,看看该评论者的int GetContributors()的结果。
我可能是错的,但我觉得你以后(我是什么,当我发现这个职位后)断言,恰好有一个集合中的每个项目,在另一个集合中的一个。
我解决了这个像这样:
Assert.IsTrue(commenters.All(c => actual.Count(p => p.Id == c.Id) == 1));
如果您还想要结果列表中不包含超过预期,你可以只比较列表的长度以及其他物品..
Assert.IsTrue(commenters.length == actual.Count());
我希望这是有帮助的,如果是的话,我会很感激,如果你会率我的答案。
Answer 8:
我建议不要使用反射或任何复杂的,它只是增加了更多的工作/维护支持。
序列化对象(我建议JSON)和字符串比较。 我不能确定你为什么反对通过订购,但我还是推荐它,因为它会保存自定义比较的每种类型。
它会自动访问域对象的变化工作。
实施例(SharpTestsEx用于流利)
using Newtonsoft.Json;
using SharpTestsEx;
JsonConvert.SerializeObject(actual).Should().Be.EqualTo(JsonConvert.SerializeObject(expected));
你可以把它写成一个简单的扩展,使之更具可读性。
public static class CollectionAssertExtensions
{
public static void CollectionAreEqual<T>(this IEnumerable<T> actual, IEnumerable<T> expected)
{
JsonConvert.SerializeObject(actual).Should().Be.EqualTo(JsonConvert.SerializeObject(expected));
}
}
然后使用你的榜样调用它像这样:
var foundCollection = fooManager.LoadFoo();
var expectedCollection = new List<Foo>()
{
new Foo() { Bar = "a", Bar2 = "b" },
new Foo() { Bar = "c", Bar2 = "d" }
};
foundCollection.CollectionAreEqual(foundCollection);
你会得到一个断言消息,如下所示:
...: “一”, “BAR2”: “B”},{ “酒吧”: “d”, “BAR2”: “d”}]
...: “一”, “BAR2”: “B”},{ “酒吧”: “C”, “BAR2”: “d”}]
... _ __ _ __ __ _ _ _ __ __ _ __ ^ __ _ _ _
Answer 9:
简单的代码说明如何使用的IComparer
using System.Collections;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace CollectionAssert
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
IComparer collectionComparer = new CollectionComparer();
var expected = new List<SomeModel>{ new SomeModel { Name = "SomeOne", Age = 40}, new SomeModel{Name="SomeOther", Age = 50}};
var actual = new List<SomeModel> { new SomeModel { Name = "SomeOne", Age = 40 }, new SomeModel { Name = "SomeOther", Age = 50 } };
NUnit.Framework.CollectionAssert.AreEqual(expected, actual, collectionComparer);
}
}
public class SomeModel
{
public string Name { get; set; }
public int Age { get; set; }
}
public class CollectionComparer : IComparer, IComparer<SomeModel>
{
public int Compare(SomeModel x, SomeModel y)
{
if(x == null || y == null) return -1;
return x.Age == y.Age && x.Name == y.Name ? 0 : -1;
}
public int Compare(object x, object y)
{
var modelX = x as SomeModel;
var modelY = y as SomeModel;
return Compare(modelX, modelY);
}
}
}
文章来源: How to assert that two list contains elements with the same public properties in NUnit?