断言该值等于任何预期值集合

时间:2014-08-27 08:20:40

标签: c# .net nunit assertions fluent-interface

NUnit是否提供约束来查找实际值是否是给定枚举或数组的元素,换句话说,它是否等于多个预期值中的任何一个?类似的东西:

Assert.That(actual, Is.EqualToAnyOf(new[] { 1, 2, 3 }))

也就是说,要指出的是,实际是单个值。我希望该值可以是123。断言

Assert.That(actual, Contains.Element(expected))

逻辑上检查相同,但这是相反的意图:这里我们有一组实际值,并期望有一个值。

此外,我发现了这些,但它们都不合适:

Assert.That(actual, Is.EqualTo(expected)) // only allows one value
Assert.That(actual, Is.InRange(start, end)) // only works for consecutive numbers
Assert.That(actual, Is.SubsetOf(expected)) // only works if actual is an enumerable
Assert.That(expected.Contains(actual)) // meaningless "expected: true but was: false" message

4 个答案:

答案 0 :(得分:4)

如果我不忽视某些事情,

CollectionAssert应该是你需要的。它很简单:

CollectionAssert.Contains(IEnumerable expected, object actual);

但是,似乎有几种方法可以实现您的目标,例如:

[Test]
public void CollectionContains()
{
    var expected = new List<int> { 0, 1, 2, 3, 5 };
    var actual = 5;

    CollectionAssert.Contains(expected, actual);
    Assert.That(expected, Contains.Item(actual));
}

以上断言应该基本断言相同,并且可以互换使用。

修改 问题被修改,说明Assert.That(expected, Contains.Item(actual));无效,即使它在逻辑上测试相同的东西。

答案 1 :(得分:2)

有一种方法可以使用Or约束来内置NUnit:

Assert.That(actual, Is.EqualTo(1).Or.EqualTo(2).Or.EqualTo(3))

如果您的列表更具动态性,您可以构建Or的列表,如下所示:

var expected = new[] { 1, 2, 3 };
var constraints = Is.EqualTo(expected[0]);

for(var i = 1; i < expected.Length; i++)
    constraints = constraints.Or.EqualTo(expected[i]);

Assert.That(actual, constraints);

后面的答案在流畅的语法中并没有读取,但确实实现了动态构建或约束。您可以将其作为patrick-quirk演示的自定义约束包装,以实现更多的readbale流体语法,但这取决于您。

答案 2 :(得分:1)

我能看到实现这一目标的唯一方法是创建自己的约束。尽管如此,这很简单。

约束类本身:

public class OneOfValuesConstraint : EqualConstraint
{
    readonly ICollection expected;
    NUnitEqualityComparer comparer = new NUnitEqualityComparer();

    public OneOfValuesConstraint(ICollection expected)
        : base(expected)
    {
        this.expected = expected;
    }

    public override bool Matches(object actual)
    {
        // set the base class value so it appears in the error message
        this.actual = actual;
        Tolerance tolerance = Tolerance.Empty;

        // Loop through the expected values and return true on first match
        foreach (object value in expected)
            if (comparer.AreEqual(value, actual, ref tolerance))
                return true;

        // No matches, return false
        return false;
    }

    // Overridden for a cleaner error message (contributed by @chiccodoro)
    public override void WriteMessageTo(MessageWriter writer)
    {
        writer.DisplayDifferences(this);
    }

    public override void WriteDescriptionTo(MessageWriter writer)
    {
        writer.Write("either of ");
        writer.WriteExpectedValue(this.expected);
    }
}

为了使它流畅,创建一个静态方法来包装它(由@chicodorro提供):

public static class IsEqual
{
    public static OneOfValuesConstraint ToAny(ICollection expected)
    {
        return new OneOfValuesConstraint(expected);
    }
}    

然后使用它:

int[] expectedValues = new[] { 0, 1, 2 };
Assert.That(6, IsEqual.ToAny(expectedValues));

信息失败:

  

预期:&lt; 0,1,2&gt;

     

但是:6

答案 3 :(得分:0)

我知道这是一个古老的问题,但是我有一个更好的(和本地的)建议。 使用NUnit 3.x(我在3.10.1上),您可以使用 Is.AnyOf

 Assert.That(
actualValue, 
Is.AnyOf(expectedValue1, expectedValue2, expectedValue3),
"My error message");