简体   繁体   English

Assert.That() 不评估给定的约束

[英]Assert.That() does not evaluate given constraint

I have a list of string values.我有一个字符串值列表。 I iterate this list with a foreach.我用 foreach 迭代这个列表。 I apply on every list item Assert.That() method.我申请了每个列表项 Assert.That() 方法。 Now comes the twist: I give as a second parameter of the method a function that returns IResolveConstraint.现在来个转折:我给出了一个返回 IResolveConstraint 的函数作为该方法的第二个参数。 When the function returns Has.Exactly(1).Contains() , then AT THE SECOND item of the list ( second iteration of the foreach ) the assertion evaluates (throws) this message: "Expected: collection containing "value"".当函数返回Has.Exactly(1).Contains()然后在列表的第二项( foreach 的第二次迭代)处,断言评估(抛出)此消息:“预期:包含“值”的集合”。 But the assertion was supposed to pass, because it was verifying exactly one item, not a collection.但是断言应该通过,因为它正在验证一个项目,而不是一个集合。

I had NUnit 3.2.1.我有 NUnit 3.2.1。 I upgraded to version 3.12.0 and after that the message changed from : "Expected: collection containing "value"" to message: "Expected: some item equal to "value"" and assertion still didn' pass.我升级到 3.12.0 版,之后消息从:“预期:包含“值”的集合”更改为消息:“预期:某些项目等于“值””并且断言仍然没有通过。


public class Verifiers
{
public void VerifyCollectedValues(List<string> collectedValues, List<string> expectedValues
, string collectedValuesFrom, int countOfValueExpactance, bool verifyExactSameValue = true)
        {
// Create a constraint function
            Func<string, IResolveConstraint> constraintFunction = CreateConstraintFunction(Has.Exactly(countOfValueExpactance), verifyExactSameValue);

// Pass the constraint to the method
            VerifyCollectedValues(constraintFunction, collectedValues, expectedValues, collectedValuesFrom);
        }

public void VerifyCollectedValues(Func<string, IResolveConstraint> constraintFunction, List<string> collectedValues, List<string> expectedValues
, string collectedValuesFrom)
        {
            foreach (string expectedValue in expectedValues)
            {
// Apply the constraint
                Assert.That(collectedValues, constraintFunction(expectedValue));             
            }
        }

public Func<string, IResolveConstraint> CreateConstraintFunction(ConstraintExpression constraintExpression, bool verifyExactSameValue)
        {
            if (verifyExactSameValue)
            {
                return (string value) => constraintExpression.EqualTo(value);
            }
            else
            {              
                return (string value) => constraintExpression.Contains(value);
            }
        }
}

Sample code:示例代码:


            Verifiers verifiers = new Verifiers(); 

            List<string> expectedValues = new List<string>()
            {
                "value1",
                "value2",
                "value3",                
            };
            var collectedValues = new List<string>()
            {
                "some_value0",
                "some_value1",
                "some_value2",
                "some_value3",
            };
// This passes
            foreach(string expectedValue in expectedValues)
            {
                Assert.That(collectedValues, Has.Exactly(1).Contains(expectedValue));
            }

// This fails with the message: "Expected: collection containing "value2"" (with NUnit v3.2.1) / "Expected: some item equal to "value2""(with NUnit v3.12.0)
            verifiers.VerifyCollectedValues(collectedValues, expectedValues, 1, false);

My assumption is that IResolveConstraint is causing the problem.我的假设是 IResolveConstraint 导致了这个问题。 What I don't understand is why the first item of list passes but the second one doesn't.我不明白的是为什么列表的第一项通过但第二项没有通过。

I'll be grateful for any answer.我将不胜感激任何答案。

UPDATE:更新:

I've done some edits and base on that I excluded the possibility that IResolveConstraint is causing the problem.我已经做了一些编辑,并在此基础上排除了 IResolveConstraint 导致问题的可能性。 Here is sample of the current code:这是当前代码的示例:


public class Verifiers
 {
        public void VerifyCollectedValues(List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom, int countOfValueExpectance, bool verifyExactSameValue = true)
        {            
            VerifyCollectedValues(CreateConstraintExpressionExactly(countOfValueExpectance), collectedValues, expectedValues, collectedValuesFrom, verifyExactSameValue);
        }

        private void VerifyCollectedValues(ConstraintExpression constraintExpression, List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom, bool exactSameValue)
        {
            if (exactSameValue)
            {
                VerifyCollectedValuesEqualTo(constraintExpression, collectedValues, expectedValues, collectedValuesFrom);
            }
            else
            {
                VerifyCollectedValuesContains(constraintExpression, collectedValues, expectedValues, collectedValuesFrom);
            }
        }

        private void VerifyCollectedValuesEqualTo(ConstraintExpression constraintExpression, List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom)
        {
            Func<string, EqualConstraint> constraintFunction = (string value) => constraintExpression.EqualTo(value);
            foreach (string expectedValue in expectedValues)
            {
                Assert.That(collectedValues, constraintFunction(expectedValue));
            }
        }

        private void VerifyCollectedValuesContains(ConstraintExpression constraintExpression, List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom)
        {
            // if I don't use constraintExpression but write the expression manually (Has.Exactly(1).Contains(value)), then it works just fine
            Func<string, ContainsConstraint> constraintFunction = (string value) => constraintExpression.Contains(value);
            foreach (string expectedValue in expectedValues)
            {
                Assert.That(collectedValues, constraintFunction(expectedValue));
            }
        }

        private ConstraintExpression CreateConstraintExpressionExactly(int countOfExpectance)
        {
            return Has.Exactly(countOfExpectance);
        }
            var verifiers = new Verifiers();

            List<string> expectedValues = new List<string>()
            {                
                "value1",
                "value2",
                "value3",                
            };
            var collectedValues = new List<string>()
            {
                "some_value0",
                "some_value1",
                "some_value2",
                "some_value3",
            };
            // This one pass successfully
            foreach(string expectedValue in expectedValues)
            {
                Assert.That(collectedValues, Has.Exactly(1).Contains(expectedValue));
            }
            // But this one still doesn't pass and fails at the second list item "value2"
            verifiers.VerifyCollectedValues(collectedValues, expectedValues, "list of strings", 1, false);

Your assumption that Has.Exactly(1).EqualTo() will pass if the actual value is a non-collection is not correct.如果实际值为非集合,您认为Has.Exactly(1).EqualTo()将通过的假设是不正确的。 ExactCountConstraint will error (not quite the same as fail) if passed a non-collection type.如果传递非集合类型, ExactCountConstraint将出错(与失败不完全相同)。

However, in this case, string is a collection of chars so it tries to run.但是,在这种情况下, string字符的集合,因此它会尝试运行。

The problem is that you are using a collection constraint, which iterates the list, but you are also iterating it yourself.问题是您正在使用集合约束,它迭代列表,但您自己也在迭代它。 You should either do it all yourself (which seems silly) or rely on the ExactCountConstraint to do the work .你要么自己做这一切(这看起来很傻),要么依靠ExactCountConstraint to do the work

If you continue to iterate the list yourself, then you should not use any collection constraints.如果您继续自己迭代列表,则不应使用任何集合约束。 In the example case, you would simply use Is.EqualTo() .在示例情况下,您只需使用Is.EqualTo()

Well, the bug is in your implementation actually, since you're passing ConstraintExpression all the time.好吧,错误实际上在您的实现中,因为您一直在传递 ConstraintExpression。 If you try to decompose the working code and create methods for each verification you'll have something like this:如果您尝试分解工作代码并为每个验证创建方法,您将得到如下内容:

[Test]
public void ListCompareTest()
{
    List<string> expectedValues = new List<string>()
    {
        "value1",
        "value2",
        "value3",
    };
    var collectedValues = new List<string>()
    {
        "some_value0",
        "some_value1",
        "some_value2",
        "some_value3",
    };
    int count = 1;
    // This one pass successfully
    foreach (string expectedValue in expectedValues)
    {
        ItemsConstraintExpression itemsConstraintExpression = GetExactly(count);
        // this code works
        Assert.That(collectedValues, GetContains(expectedValue, itemsConstraintExpression));
    }
    // this code works as well
    DoVerification(expectedValues, collectedValues, 1, false);
}

public static void DoVerification(List<string> expectedList, List<string> actualList, int exactlyCount, bool equalsOrContains)
{
    if (equalsOrContains)
    {
        foreach (var expectedValue in expectedList)
        {
            Assert.That(actualList, GetEquals(expectedValue, GetExactly(exactlyCount)));
        }
    }
    else
    {
        foreach (var expectedValue in expectedList)
        {
            Assert.That(actualList, GetContains(expectedValue, GetExactly(exactlyCount)));
        }
    }
}

private static EqualConstraint GetEquals(string expectedValue, ItemsConstraintExpression itemsConstraintExpression)
{
    return itemsConstraintExpression.EqualTo(expectedValue);
}

private static ContainsConstraint GetContains(string expectedValue, ItemsConstraintExpression itemsConstraintExpression)
{
    return itemsConstraintExpression.Contains(expectedValue);
}

private static ItemsConstraintExpression GetExactly(int count)
{
    return Has.Exactly(count);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM