简体   繁体   中英

Assert.That() does not evaluate given constraint

I have a list of string values. I iterate this list with a foreach. I apply on every list item Assert.That() method. Now comes the twist: I give as a second parameter of the method a function that returns 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"". But the assertion was supposed to pass, because it was verifying exactly one item, not a collection.

I had 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.


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. 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. 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. ExactCountConstraint will error (not quite the same as fail) if passed a non-collection type.

However, in this case, string is a collection of chars so it tries to run.

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 .

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() .

Well, the bug is in your implementation actually, since you're passing ConstraintExpression all the time. 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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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