I'm Keyvan Nayyeri, a 25 years old Ph.D. student at
the Computer Science department of
the University of Texas at San Antonio.
I'm also
a Software Architect and Developer and previously held a B.Sc.
degree in Applied Mathematics.
This is my blog where I publish content about various topics specifically Programming Languages and Compilers, Software
Engineering and Programming.
If you do unit tests frequently, know that unit testing a generic list is a very common scenario because generic lists are a common part of today's codes in the .NET world.
Testing the equality of two generic lists isn't as easy as easy testing the equality of two objects from two simple types. In order to test two generic lists, you need to follow one of two approaches that I describe in this post. One of them is easy and can be done quickly and the second one may need more effort.
First suppose that you have a Person class like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericList
{
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Sex { get; set; }
public Person()
{
}
public Person(string firstName, string lastName, int age, string sex)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Age = age;
this.Sex = sex;
}
}
}
And also suppose that you have another class named PersonCollection derived from generic list of Person.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericList
{
public class PersonCollection : List<Person>
{
public Person GetOldest()
{
int maxAge = 0;
Person chosenPerson = new Person();
foreach (Person person in this)
{
if (person.Age > maxAge)
{
maxAge = person.Age;
chosenPerson = person;
}
}
return chosenPerson;
}
}
}
Now I write a People class that doesn't have anything but a List property of PersonCollection type.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericList
{
public class People
{
public PersonCollection List { get; set; }
}
}
The first approach, and the approach that I personally would prefer to the second one, is overriding the Equals method for the generic list class in your code. In this case, when you call Assert.AreEqual to check the equality of two lists of this type, then it can compare two lists in the right way that you teach to it.
In the above example, I can update the PersonCollection class to override the Equals method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericList
{
public class PersonCollection : List<Person>
{
public Person GetOldest()
{
int maxAge = 0;
Person chosenPerson = new Person();
foreach (Person person in this)
{
if (person.Age > maxAge)
{
maxAge = person.Age;
chosenPerson = person;
}
}
return chosenPerson;
}
public override bool Equals(object obj)
{
PersonCollection input = obj as PersonCollection;
if (input.Count != this.Count)
return false;
for (int index = 0; index < input.Count; index++)
{
Person inputPerson = input[index];
Person originalPerson = this[index];
if ((inputPerson.FirstName != originalPerson.FirstName) ||
(inputPerson.LastName != originalPerson.LastName) ||
(inputPerson.Age != originalPerson.Age) ||
(inputPerson.Sex != originalPerson.Sex))
return false;
}
return true;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}
Now I can write a test method to test the List property of People class.
/// <summary>
///A test for List
///</summary>
[TestMethod()]
public void ListTest()
{
People target = new People();
PersonCollection expected = new PersonCollection();
expected.Add(new Person("Keyvan", "Nayyeri", 23, "Male"));
expected.Add(new Person("Mehrdad", "Ebrahimi", 24, "Male"));
PersonCollection actual = new PersonCollection();
target.List = expected;
actual = target.List;
Assert.AreEqual(expected, actual);
}
For two reasons this may be hard or impossible for you:
Despite these two negative points, this approach is better because:
The second approach is easier to achieve but works as just a testing solution and can't provide abovementioned benefits for you.
You can simply write a generic test method that gets two generic lists and tests them on fly.
/// <summary>
///A test for List
///</summary>
[TestMethod()]
public void ListTest()
{
People target = new People();
PersonCollection expected = new PersonCollection();
expected.Add(new Person("Keyvan", "Nayyeri", 23, "Male"));
expected.Add(new Person("Mehrdad", "Ebrahimi", 24, "Male"));
PersonCollection actual = new PersonCollection();
target.List = expected;
actual = target.List;
GenericTest<Person>(expected, actual);
}
private void GenericTest<T>(List<T> actual, List<T> expected)
{
IEnumerator<T> actualEnumerator = actual.GetEnumerator();
for (int i = 0; i < expected.Count; i++)
{
Assert.IsTrue(actualEnumerator.MoveNext());
Assert.IsTrue(actualEnumerator.Current.Equals(expected[i]));
}
Assert.IsFalse(actualEnumerator.MoveNext());
}
This is a quick way and I use it when want to test codes faster!
DotNetKicks.com
Sep 30, 2007 7:01 PM
#
Greg Young
Nov 22, 2007 6:52 PM
#
Leave a Comment