Date:

Share:

MSTest CollectionAssert class – an overview

Related Articles

This is the third part of our journey. In the first part we listed the methods belonging to load in class, while in the second part we looked at StringAssert status.

Now let’s dive deep into the CollectionAssert class, which is suitable for ensuring that a collection of elements follows the desired specifications.

Introduction to CollectionAssert

this class Checks various conditions related to collections, such as element type checks. It is important to say that this class does not check whether each element in the collection follows a certain rule (like “the ID must be greater than 0”), but it is more about High level testing.

For these examples I will reuse two classes created for the first article in this series: user and AdminUser: The second class expands the first:

public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
}

public class AdminUser : User
{
    public string Department { get; set; }
}

CollectionAssert.AllItemsAreInstancesOfType

With this method we can check if all the elements belonging to the collection are of the same type.

A simple example would be the one with a list of strings.

[TestMethod]
public void AllItemsAreInstanceOfType_String()
{
    string[] stringArray = new string[] { "Hello", "darkness", "my", "old", "friend" };

    CollectionAssert.AllItemsAreInstancesOfType(stringArray, typeof(string));
}

Of course all the elements in stringArray Arrays are all strings, so it’s easy to guess that the test will pass.

What about an object? In the next test I will create a list of User elements, but with also a AdminUser resist. You should remember that AdminUser is also a user, but the opposite is not true.

[TestMethod]
public void AllItemsAreInstanceOfType_AreAllUsers()
{
    List<User> list = new List<User>()
    {
        new User(){ Username = "Elvis", Id=1},
        new User(){ Username="Janis", Id=2},
        new AdminUser(){ Username="Freddie", Id=3, Department="Legends"}
    };

    CollectionAssert.AllItemsAreInstancesOfType(list, typeof(User)); 
    CollectionAssert.AllItemsAreInstancesOfType(list, typeof(AdminUser)); 
}

The first test will pass, but the second will fail because the object with username = “freddy” is the only object of its type AdminUser.

CollectionAssert.AllItemsAreNotNull

This method is quite simple: if an element in the collection is null It will fail.

[TestMethod]
public void AllItemsAreNotNull()
{
    List<User> list = new List<User>() {
        new User(){Username= "Elvis", Id=1},
        null,
        new AdminUser(){ Username="Freddie", Id=3, Department="Legends"}
    };

    CollectionAssert.AllItemsAreNotNull(list);
}

Of course the above test will fail.

CollectionAssert.AllItemsAreUnique

The name explains.

The test below will pass:

[TestMethod]
public void AreAllItemsUnique_integers()
{
    int[] array = new int[] { 1, 2, 3, 9, 7 };
    CollectionAssert.AllItemsAreUnique(array);
}

But life is not meant to be lived with only whole numbers. And here things get a little more difficult.

[TestMethod]
public void AreAllItemsUnique_Users()
{
    User[] array = new User[] {
        new User(){Username= "Elvis", Id=1},
        new User(){Username= "Elvis", Id=1}
    };
    CollectionAssert.AllItemsAreUnique(array);
}

Well, Elvis will forever be unique… but not here! God array A variable contains two different instances of User, even if the properties have the same value. then this test will fail.

Dig a little deeper into AllItemsAreUnique In the class we can see that internally it works with dictionaries:

public static void AllItemsAreUnique(ICollection collection, string message, params object[] parameters)
{
	Assert.CheckParameterNotNull(collection, "CollectionAssert.AllItemsAreUnique", "collection", string.Empty);
	message = Assert.ReplaceNulls(message);
	bool flag = false;
	Dictionary<object, bool> dictionary = new Dictionary<object, bool>();
	foreach (object item in collection)
	{
		if (item == null)
		{
			if (!flag)
			{
				flag = true;
			}
			else
			{
				string message2 = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AllItemsAreUniqueFailMsg, new object[2]
				{
					(message == null) ? string.Empty : message,
					FrameworkMessages.Common_NullInMessages
				});
				Assert.HandleFail("CollectionAssert.AllItemsAreUnique", message2, parameters);
			}
		}
		else if (dictionary.ContainsKey(item))
		{
			string message3 = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AllItemsAreUniqueFailMsg, new object[2]
			{
				(message == null) ? string.Empty : message,
				Assert.ReplaceNulls(item)
			});
			Assert.HandleFail("CollectionAssert.AllItemsAreUnique", message3, parameters);
		}
		else
		{
			dictionary.Add(item, value: true);
		}
	}
}

Ok, it’s not that exciting, but I wanted to show you what’s under the hood and how to handle the comparison.

So let’s get back to our problem: How can we make this test pass?

We have to bypass the Equals And the GetHashCode method. Even here I reuse the UpdatedUser Class from the first article

public class UpdatedUser
{
    public int Id { get; set; }
    public string Username { get; set; }
    public override bool Equals(object obj)
    {
        return Id == ((User)obj).Id;
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

Now the test will pass.

CollectionAssert.AreEqual

If you want to check if two collections are the same, you can use AreEqual. It checks if the same elements are in the same position in both collections.

For example, this test would pass:

[TestMethod]
public void AreEqual_Int()
{
    int[] array1 = new int[] { 1, 2, 3, 4, 5, 6 };
    int[] array2 = new int[] { 1, 2, 3, 4, 5, 6 };
    CollectionAssert.AreEqual(array1, array2); 
}

But the following will fail:

[TestMethod]
public void AreEqual_DifferentPosition_Int()
{
    int[] array1 = new int[] { 1, 2, 3, 5, 4, 6 };
    int[] array2 = new int[] { 1, 2, 3, 4, 5, 6 };
    CollectionAssert.AreEqual(array1, array2); 
}

As we saw earlier, with simple objects this does not work:

[TestMethod]
public void AreEqual_Objects()
{
    List<User> list = new List<User>()
    {
        new User(){ Username = "Elvis", Id=1},
        new User(){ Username="Janis", Id=2},
        new AdminUser(){ Username="Freddie", Id=3, Department="Legends"}
    };

    List<User> list2 = new List<User>()
    {
        new User(){ Username = "Elvis", Id=1},
        new User(){ Username="Janis", Id=2},
        new AdminUser(){ Username="Freddie", Id=3, Department="Legends"}
    };

    CollectionAssert.AreEqual(list, list2);
}

You should use the UpdatedUser in class to make it work.

[TestMethod]
public void AreEqual_ObjectsWithOverride()
{
    List<UpdatedUser> list = new List<UpdatedUser>()
    {
        new UpdatedUser(){ Username = "Elvis", Id=1},
        new UpdatedUser(){ Username="Janis", Id=2}
    };

    List<UpdatedUser> list2 = new List<UpdatedUser>()
    {
        new UpdatedUser(){ Username = "Elvis", Id=1},
        new UpdatedUser(){ Username="Janis", Id=2}
    };

    CollectionAssert.AreEqual(list, list2);
}

What about buildings? Well, you can imagine, everything is fine.

[TestMethod]
public void AreEqual_Structs()
{
    List<Employee> list = new List<Employee>()
    {
        new Employee(){ Age = 11, Id=1},
        new Employee(){ Age= 92, Id=2}
    };

    List<Employee> list2 = new List<Employee>()
    {
        new Employee(){ Age = 11, Id=1},
        new Employee(){ Age= 92, Id=2}
    };

    CollectionAssert.AreEqual(list, list2);
}

CollectionAssert.AreEquivalent

On time AreEqual Checking if two collections are the same, there is a shallower way to check two collections. AreEquivalent Controls whether the same elements are in both collections, regardless of their position.

[TestMethod]
public void AreEquivalent_Int()
{
    int[] array1 = new int[] { 1, 2, 3, 4, 5, 6 };
    int[] array2 = new int[] { 4, 5, 6, 1, 2, 3 };
    CollectionAssert.AreEquivalent(array1, array2); 
}

CollectionAssert.Contains

Ok, this method is easy to guess why it is used for…

[TestMethod]
public void Contains_Int()
{
    int[] array1 = new int[] { 1, 2, 3, 4, 5, 6 };
    CollectionAssert.Contains(array1, 5); 
}

CollectionAssert.IsSubsetOf

Even here it’s pretty easy.

[TestMethod]
public void IsSubsetOf_Int()
{

    int[] array1 = new int[] { 1, 2, 3, 4, 5, 6 };
    int[] subset = new int[] { 2, 3 };
    CollectionAssert.IsSubsetOf(subset, array1); 
}

finishing

We had a review of CollectionAssert status. I think it’s very useful for checking if a collection is “well-formed”, checking the content type and presence of an item. But it’s better to also have a method for checking if a custom condition is honored by all elements of the collection, for example specifying a lambda expression to evaluate for each element.

This article first appeared on Code4IT

Summary

This is the end of this journey through pain and joy. As you can see, MSTest is suitable for basic tests, but if you want something more complete I suggest using other libraries.

My favorite, so far, is FluentAssertion. It replaces the Assert A class with syntax that allows you to create more complex tests. It’s more readable (well, current) and a test looks like this:

[TestMethod]
public void MustContain()
{

    int[] array = new int[] { 1, 2, 3, 4, 5 };

    array.Should().Contain(4);
}

I think MSTest is perfect if you are taking your first steps in the world of unit testing, but as the complexity increases you should consider adopting other frameworks.

.

Source

Popular Articles