簡體   English   中英

測試集合不包含多個成員

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM