[英]Test collection does not contain several members
考慮以下代碼:
const string user8 = "user8";
const string user9 = "user9";
string[] users = { "user1", "user2", "user3", "user4", user8 };
我想測試users
不包含user8或user9。 我以前用過
Assert.That(users, Is.Not.SupersetOf(new[] {user8, user9 }));
不幸的是,它通過了測試(這不是預期的)。 我可以用
Assert.That(users, Does.Not.Contains(user8).And.Not.Contains(user9));
但如果我打算再次測試超過2名成員的收集,那將是有問題的。 有沒有更好的語法? 我正在使用NUnit 3.4。
注意:目標不僅僅是測試結果,而應該是正確的斷言,因此每當測試失敗時,我們可以從錯誤消息中更快地確定。 這是上一個示例中的錯誤消息示例(使用Does.Not.Contains
)
“預期:不包含”user8“且不包含”user9“的集合但是:<”user1“,”user2“,”user3“,”user4“,”user8“>”
嘗試使用CollectionAssert.IsNotSubsetOf()
CollectionAssert.IsNotSubsetOf(new[] {user8Name, user9Name }), users);
更新:
好吧,你總是可以使用基本的循環。
Array.ForEach(new[] { user8, user9 }, u => Assert.That(users, Has.No.Member(u)));
這將通過循環檢查users
是否在new[] { user8, user9 }
數組中包含任何實例。
錯誤消息將是這樣的:
預期:不包含“user8”的集合但是:<“user1”,“user8”,“user2”,“user3”>
嘗試檢查針對用戶的排除列表
const string user8 = "user8";
const string user9 = "user9";
string[] users = { "user1", "user2", "user3", "user4", user8 };
Assert.Multiple(() => {
var exclude = new[] { user8, user9 };
foreach(var user in exclude) {
Assert.That(users, Has.No.Member(user));
}
}
此測試應該失敗,因為用戶列表確實包含user8
NUnit文檔 - CollectionContainsConstraint
在深入研究創建自定義約束和下載NUnit源代碼之后,我決定創建自定義CollectionContainsConstraint a
/// <summary>
/// CollectionContainsAnyConstraint is used to test whether a collection
/// contains any member in expected collection.
/// </summary>
/// <typeparam name="T"></typeparam>
public class CollectionContainsAnyConstraint<T> : CollectionContainsConstraint
{
public CollectionContainsAnyConstraint(IEnumerable<T> expected) : base(expected)
{
}
public override string Description
=> Regex.Replace(base.Description, @"^\s*collection containing", "collection containing any of");
/// <summary>
/// Test whether any member in expected collection is available in actual collection
/// </summary>
/// <param name="actual">Actual collection</param>
/// <returns></returns>
protected override bool Matches(IEnumerable actual)
{
var convertedExpected = (IEnumerable<T>)Expected;
var convertedActual = EnsureHasSameGenericType(actual, typeof(T));
return convertedActual.Any(x => convertedExpected.Contains(x));
}
private IEnumerable<T> EnsureHasSameGenericType(IEnumerable actual, Type expectedType)
{
var sourceType = actual.GetType();
var sourceGeneric = sourceType.IsArray
? sourceType.GetElementType()
: sourceType.GetGenericArguments().FirstOrDefault();
if (sourceGeneric == null)
throw new ArgumentException("The actual collection must contain valid generic argument");
if (!sourceGeneric.Equals(expectedType))
throw new ArgumentException($"The actual is collection of {sourceGeneric.Name} but the expected is collection of {expectedType.Name}");
return (IEnumerable<T>)actual;
}
}
public static class ConstraintExtensions
{
/// <summary>
/// Returns a new <see cref="CollectionContainsAnyConstraint{T}"/> checking for the
/// presence of any object of the <see cref="expected"/> collection against actual collection.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression"></param>
/// <param name="expected">A collection where one of its member is available in actual collection</param>
/// <returns></returns>
public static CollectionContainsAnyConstraint<T> ContainsAny<T>(this ConstraintExpression expression,
params T[] expected)
{
var constraint = new CollectionContainsAnyConstraint<T>(expected);
expression.Append(constraint);
return constraint;
}
}
用法看起來像這樣
[TestFixture]
class GivenCustomCollectionContainsTest
{
const string User8 = "user8";
const string User9 = "user9";
private readonly List<string> users = new List<string> { "user1", "user2", "user3", "user4", "user5" };
[Test]
public void WhenActualContainsOneOfExpectedAndPreceededByNotOperatorThenItShouldFail()
{
var actual = users.ToList();
actual.Add(User8);
var assert = Assert.Throws<AssertionException>(() => Assert.That(actual, Does.Not.ContainsAny(User8, User9)));
Assert.That(assert.ResultState.Status, Is.EqualTo(TestStatus.Failed));
Assert.That(assert.Message, Does.Contain("not collection containing any of").And.Contain($"\"{User8}\""));
}
[Test]
public void WhenActualContainsAllOfExpectedAndPreceededByNotOperatorThenItShouldFail()
{
var actual = users.ToList();
actual.Add(User8);
actual.Add(User9);
var assert = Assert.Throws<AssertionException>(() => Assert.That(actual, Does.Not.ContainsAny(User8, User9)));
Assert.That(assert.ResultState.Status, Is.EqualTo(TestStatus.Failed));
Assert.That(assert.Message, Does.Contain("not collection containing any of").And.Contain($"\"{User8}\", \"{User9}\""));
}
}
請注意,這僅用於負面測試。 幸運的是,我現在不需要測試“集合的任何成員在另一個集合中可用”。 大多數情況下,它測試集合是另一個集合的一部分,因此,我可以使用Is.SupersetOf
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.