How to assert that two list contains elements with the same public properties in NUnit?

后端 未结 10 1741
日久生厌
日久生厌 2021-02-04 02:20

I want to assert that the elements of two list contains values that I expected, something like:

var foundCollection = fooManager.LoadFoo();
var expectedCollectio         


        
相关标签:
10条回答
  • 2021-02-04 02:52

    One option is to write custom constraints to compare the items. Here's a nice article on the subject: http://www.davidarno.org/2012/07/25/improving-nunit-custom-constraints-with-syntax-helpers/

    0 讨论(0)
  • 2021-02-04 02:53

    REWORKED ANSWER

    There is a CollectionAssert.AreEqual(IEnumerable, IEnumerable, IComparer) overload to assert that two collections contain the same objects in the same order, using an IComparer implementation to check the object equivalence.

    In the scenario described above, the order is not important. However, to sufficiently handle also the situation where there are multiple equivalent objects in the two collections, it becomes necessary to first order the objects in each collection and use one-by-one comparison to ensure that also the number of equivalent objects are the same in the two collections.

    Enumerable.OrderBy provides an overload that takes an IComparer<T> argument. To ensure that the two collections are sorted in the same order, it is more or less required that the types of the identifying properties implement IComparable. Here is an example of a comparer class that implements both the IComparer and IComparer<Foo> interfaces, and where it is assumed that Bar takes precedence when ordering:

    public class FooComparer : IComparer, IComparer<Foo>
    {
        public int Compare(object x, object y)
        {
            var lhs = x as Foo;
            var rhs = y as Foo;
            if (lhs == null || rhs == null) throw new InvalidOperationException();
            return Compare(lhs, rhs);
        }
    
        public int Compare(Foo x, Foo y)
        {
            int temp;
            return (temp = x.Bar.CompareTo(y.Bar)) != 0 ? temp : x.Bar2.CompareTo(y.Bar2);
        }
    }
    

    To assert that the objects in the two collections are the same and comes in equal numbers (but not necessarily in the same order to begin with), the following lines should do the trick:

    var comparer = new FooComparer();
    CollectionAssert.AreEqual(
        expectedCollection.OrderBy(foo => foo, comparer), 
        foundCollection.OrderBy(foo => foo, comparer), comparer);    
    
    0 讨论(0)
  • 2021-02-04 02:55

    I had a similar problem. Listing contributors, which contains "commenters" and other ppl... I want to get all the comments and from that derive the creators, but I'm ofc only interested in unique creators. If someone created 50 comments I only want her name to appear once. So I write a test to see that the commenters are int the GetContributors() result.

    I may be wrong, but what I think your after (what I was after when I found this post) is to assert that there are exactly one of each item in one collection, found in another collection.

    I solved this like so:

    Assert.IsTrue(commenters.All(c => actual.Count(p => p.Id == c.Id) == 1));
    

    If you also want the resulting list not to contain other items than expected you could just compare the length of the lists as well..

    Assert.IsTrue(commenters.length == actual.Count());
    

    I hope this is helpful, if so, I'd be very grateful if you would rate my answer.

    0 讨论(0)
  • 2021-02-04 02:57

    To perform equivilance operations on complex types you need to implement IComaprable.

    http://support.microsoft.com/kb/320727

    Alternatively you could use recursive reflection, which is less desirable.

    0 讨论(0)
  • 2021-02-04 02:58

    Have you tried something like this?

    Assert.That(expectedCollection, Is.EquivalentTo(foundCollection))
    
    0 讨论(0)
  • 2021-02-04 02:59

    I recommend against using reflection or anything complex, it just adds more work/maintenace.

    Serialize the object (i recommend json) and string compare them. I'm unsure why you object to order by but I'd still recommend it as it will save a custom compare's for each type.

    And it automatically works with domain objects change.

    Example (SharpTestsEx for fluent)

    using Newtonsoft.Json;
    using SharpTestsEx;
    
    JsonConvert.SerializeObject(actual).Should().Be.EqualTo(JsonConvert.SerializeObject(expected));
    

    You can write it as a simple extensions and make it more readable.

       public static class CollectionAssertExtensions
        {
            public static void CollectionAreEqual<T>(this IEnumerable<T> actual, IEnumerable<T> expected)
            {
                JsonConvert.SerializeObject(actual).Should().Be.EqualTo(JsonConvert.SerializeObject(expected));
            }
        }
    

    and then using your example call it like so:

    var foundCollection = fooManager.LoadFoo();
    var expectedCollection = new List<Foo>() 
    {
        new Foo() { Bar = "a", Bar2 = "b" },
        new Foo() { Bar = "c", Bar2 = "d" }
    };
    
    
    foundCollection.CollectionAreEqual(foundCollection);
    

    You'll get an assert message like so:

    ...:"a","Bar2":"b"},{"Bar":"d","Bar2":"d"}]

    ...:"a","Bar2":"b"},{"Bar":"c","Bar2":"d"}]

    ...__________________^_____

    0 讨论(0)
提交回复
热议问题