0

I have a problem using Fluent Assertions to compare two collections of type List<List<string>>. When using the Should().Equal() method (order is important) I get the following (cryptic ;-) message:

Expected collection to be equal to {{"Telefoonnummer"}, {"E-mailadres"}, {"E-mailadres controle"}}, but {{"Telefoonnummer"}, {"E-mailadres"}, {"E-mailadres controle"}} differs at index 0.

So, the objects appear to be equal. Also when debugging the objects appear to be exactly the same. When comparing two List<string> objects the test passes, no problems, but the same test with List<List<string>> fails. Am I using the wrong assertion method? Or does Fluent Assertions not handle this type of collection correctly?

Veverke
  • 9,208
  • 4
  • 51
  • 95
jvanderwoude
  • 17
  • 2
  • 5

2 Answers2

2

Instead of Should().Equal() use actualList.ShouldBeEquivalentTo(expectedList. config => config.WithStrictOrder());

ShouldBeEquivalentTo method will check that both lists contains items with same values. In cases when list contains instance of reference types, it will compare the full object graph of those instances. Adding as a second parameter
config => config.WithStrictOrdering() will check that order of items is same as in expected list.

Should().Equal() on other hand will use "standard" equality check, where var listOne = new List<string> { "test" }; and var listTwo = new List<string> { "test" }; will be different instances.

mbabramo
  • 2,573
  • 2
  • 20
  • 24
Fabio
  • 31,528
  • 4
  • 33
  • 72
0

While comparing a string using == checks value equality, List<string> checks the address of the list. This means two lists, containing the same elements are not the same because you are comparing the addresses of the lists instead of the items inside. Lets make an example:

List<string> listA = new List<string> { "item" };
List<string> listB = new List<string> { "item" };
bool equal = listA == listB; //equal will be false

To solve your problem you could combine SelectMany and SequenceEqual to compare the items inside the lists. Here is a small example:

List<List<string>> listToCompare = new List<List<string>>()
{
    new List<string> {"first", "second"},
    new List<string> {"third"}
};
List<string> expectedList = new List<string> { "first", "second", "third" };
bool sequenceEqual = listToCompare.SelectMany(i => i).SequenceEqual(expectedList); //sequenceEqual will be true
Fruchtzwerg
  • 10,999
  • 12
  • 40
  • 49
  • Thanks for the answer, I didn't realize that! Now I'm reconsidering if I need `List>` at all, maybe `List` will suffice. Certainly when the expectedList in your example already is of that type. – jvanderwoude Apr 23 '17 at 14:15
  • Or is it possible to compare two objects of type `List>` at all? – jvanderwoude Apr 23 '17 at 14:17
  • _While string is a value type_ - `string` is reference type, `Reference.Equals(firstStringWithWordTest, secondStringWithWordTest)` - will return false because both arguments are different instances. But `firstStringWithWordTest == secondStringWithWordTest` will return true, because string equality checks for value equality. – Fabio Apr 23 '17 at 14:29
  • Totally correct @Fabio ... this was a little bit unlucky ... I've corrected this. Thanks! – Fruchtzwerg Apr 23 '17 at 14:33
  • @jvanderwoude Yes comparing to `List>` is possible like `nestedListA.SelectMany(i => i).SequenceEqual(nestedListB.SelectMany(i => i));` – Fruchtzwerg Apr 23 '17 at 14:36
  • Thanks. Tried all solutions, the `SequenceEqual` is nice but does not give the wanted information when it fails. `ShouldBeEquivalentTo` suits my needs better. – jvanderwoude Apr 23 '17 at 15:24