ASP.Net XUnit check if list of objects cointains a specific object

Viewed 5629

I am trying to add unit tests to my project. Some of these tests are checking if a list of objects does of does not contain an object. For checking if a list contains an object i've tried Assert.Contains(MyList, ExpectedObject), but it still gives an error that says that the list does not contain this object. Even when i debug the test i can see that the object is correctly added to the list.

The same happens with Assert.DoesNotContain(MyList, ExpectedObject). When i remove an item from the list and do this check it does say that it not in the list. But when i no longer remove the item, it still says that it is no longer in the list. Even though it is still in the list.

When i try it with a test list:List<string>. and do the same operations of adding and removing items, and then checking if these items are in the list or not. It does work. Maybe Assert.Contains does not work for lists of objects. But the compiler does not give any errors. And i've also already checked if the ExpectedObject is the same type as the objects in the list.

Is there maybe another way of checking if an object is or isn't in a list. any help is appreciated.

3 Answers

In your test, is ExpectedObject the actual object in the list or an object with the same values? In C# two objects with the same property values are not actually equal. I suspect this is why your test is failing. Two strings with the same value are considered equal because the string object implements the Equals method (and some more), like @dorukerenaktas points out.

There's multiple ways to go about this. The easiest is by checking if an object with the expected property values is in the collection.

There's an overload of Assert.Contains that allows you to specify a predicate, for example:

Assert.Contains(MyList, item => item.Id == expectedId)

Another option is to override the Equals method on your object, like @dorukerenaktas explains, but I would only recommend that if it really makes sense for your class. I would definitely not do that just so you can use this in a test.

Generally in Java and C# implementation of contains methods for object lists compare them by equals method. If equals method if not specified for the object by default it will look for object unique id or memory address, it means even if there were 2 objects with all same fields can be different. Because they created separately and allocated different ram addresses. If you want to compare objects override equals method. This will allow contains method to compare objects with each other using your custom comparison method.

Example:

Let say you have a Person object with fields like id, name, mail etc. If you want objects to be equal if their id's are same you can use:

// They are same person if their id is same
public override bool Equals(Object obj)
   {
      Person personObj = obj as Person;
      if (personObj == null)
         return false;
      else
         return idNumber.Equals(personObj.idNumber);
   }

I have faced a similar problem before and I used fluentAssertions to solve it.

So for example if you have a list of objects called myList, this snipped should do the trick.

myList.Should().Contain(expectedItem);

There is more info on collections here: https://fluentassertions.com/collections/

The other option is to loop through the list and check if any of the objects are equal to your object. When doing this, if you use the ShouldBeEquivalentTo() method you will not need to check equality of every property. This is very useful if your object is large or nested, since this method checks each property recursively.

actual.Should().BeEquivalentTo(expected);

There is more information on this here: https://fluentassertions.com/objectgraphs/

I like using fluentAssetions because it makes my tests and assertions more readable, and also provides very clear messages when errors do occurs or assertions fail, so you find the problem faster.

Related