Blogs

According to Wikipedia,

In computer science, reflection is the ability of a computer program to examine and modify the structure and behavior (specifically the values, meta-data, properties and functions) of an object at runtime.

C# Reflection follows exactly this definition providing a powerful tool to achieve many advanced level coding tasks. One of the benefits when using C# Reflection is helping developers to write less code leading, thus saving coding efforts and time and raising coding quality. Let's see how it is applied in unit/integration tests with sample code.

1. Using C# Reflection in preparing sample data

I want to test a web service method that has this contract:

[ServiceContract]
public interface IFooService
{
     [OperationContract]
     Collection<FooUser> SaveFooUsers(Collection<FooUser> fooUsers);
}

public class FooService : IFooService
{
     // Implement the operation contracts here
}

Here is the FooUser data contract:

[DataContract]
public class FooUser
{
     [DataMember]
     public Guid FooUserGuid { get; set; }
     [DataMember]
     public string FirstName { get; set; }
     [DataMember]
     public string LastName { get; set; }
     [DataMember]
     public int Age { get; set; }
     [DataMember]
     public string Phone { get; set; }
     [DataMember]
     public string Address { get; set; }
     [DataMember]
     public string Email { get; set; }
}

Normally when writing a test for saving 3 FooUsers, without using C# Reflection, the test method would be like this:

[TestMethod]  
 public void FooService_SaveFooUsers_ReturnExpectedResult()  
 {  
   //Arrange  
   FooUser firstFooUser = new FooUser()  
   { 
     FooUserGuid = Guid.NewGuid(), 
     Address = "Address1",  
     Age = 20,  
     Email = "Email1@abc.com",  
     FirstName = "FirstName1",  
     LastName = "LastName1",  
     Phone = "Phone1"  
   };      
   FooUser secondFooUser = new FooUser()  
   { 
     FooUserGuid = Guid.NewGuid(), 
     Address = "Address2",  
     Age = 21,  
     Email = "Email2@abc.com",  
     FirstName = "FirstName2",  
     LastName = "LastName2",  
     Phone = "Phone2"  
   };  
   FooUser thirdFooUser = new FooUser()  
   { 
     FooUserGuid = Guid.NewGuid(), 
     Address = "Address3",  
     Age = 22,  
     Email = "Email3@abc.com",  
     FirstName = "FirstName3",  
     LastName = "LastName3",  
     Phone = "Phone3"  
   };  
   Collection<FooUser> expected = new Collection<FooUser>() { firstFooUser, secondFooUser, thirdFooUser };  
   //Act  
   Collection<FooUser> actual = FooService.SaveFooUsers(expected);  
   //Assert two collections here
 }

As you can see, the test method is very simple. However, to create the sample data required many lines and they almost all look the same. By using C# Reflection, we will be able to write less code for this test method.

Let's start by creating a PopulateSampleData helper method using C# Reflection and Generics. It's best to put this method in a Utility class so that we can reuse it our other test methods too.

public static class Utility  
{  
   public static T PopulateSampleData()  
   {  
     // Random instance is used for populate auto data  
     Random ran = new Random();  
     Type type = typeof(T);  
     T contract = (T)Activator.CreateInstance(type);  
     foreach (PropertyInfo property in type.GetProperties())  
     {  
       Type propertyType = property.PropertyType;  
       if (propertyType == typeof(string))  
         property.SetValue(contract, Guid.NewGuid().ToString().Substring(0, 10), null);  
       if (propertyType == typeof(int) || propertyType == typeof(int?))  
         property.SetValue(contract, ran.Next(), null);  
       if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))  
         property.SetValue(contract, DateTime.UtcNow, null);  
       if (propertyType == typeof(bool) || propertyType == typeof(bool?))  
         property.SetValue(contract, false, null);  
       if (propertyType == typeof(Guid) || propertyType == typeof(Guid?))  
         property.SetValue(contract, Guid.NewGuid(), null);   
     }  
     return contract;  
   }  
}

Using the helper method to populate sample data, the test method will be revised like this:

[TestMethod]  
public void FooService_SaveFooUsers_ReturnExpectedResult()  
{  
   //Arrange  
   FooUser firstFooUser = Utility.PopulateSampleData<FooUser>();      
   FooUser secondFooUser = Utility.PopulateSampleData<FooUser>();  
   FooUser thirdFooUser = Utility.PopulateSampleData<FooUser>();  
   Collection<FooUser> expected = new Collection<FooUser>() { firstFooUser, secondFooUser, thirdFooUser };  
   //Act  
   Collection<FooUser> actual = FooService.SaveFooUsers(expected);  
   //Assert two collections here
}

By using some simple C# Reflection techniques we can reduce coding efforts in creating sample data (which is boring and time-consuming). Additionally, the code is sorted and much cleaner.

2. Using C# Reflection in asserting two reference type objects

MSTest and NUnit are two most popular unit test frameworks and they provide a wide range of Assert methods. However when coming to assert reference type objects, they do not really provide us any methods to achieve that. Therefore engineers usually need to figure out a way to assert reference type objects by themselves. A common approach that they usually choose is explicitly asserting each property of specific objects and when all of them are equal, the test passes.

[TestMethod]  
public void FooService_SaveASingleFooUser_ReturnExpectedResult()  
{  
   //Arrange  
   FooUser sampleFooUser = Utility.PopulateSampleData<FooUser>();      
   Collection<FooUser> expected = new Collection<FooUser>() { sampleFooUser };  
   //Act  
   Collection<FooUser> actual = FooService.SaveFooUsers(expected);  
   //Assert 
   Assert.AreEqual(expected[0].FooUserGuid, actual[0].FooUserGuid);
   Assert.AreEqual(expected[0].Address,     actual[0].Address);
   Assert.AreEqual(expected[0].Age,         actual[0].Age);
   Assert.AreEqual(expected[0].Email,       actual[0].Email);
   Assert.AreEqual(expected[0].FirstName,   actual[0].FirstName);
   Assert.AreEqual(expected[0].LastName,    actual[0].LastName);
   Assert.AreEqual(expected[0].Phone,       actual[0].Phone);
}

A few senior engineers would recommend to override .Equal method in those objects so that we can just call Assert.AreEqual(expected[0], actual[0]). Wow this idea is fabulous, this not only help us to write less code in our tests but also encapsulate the comparison inside objects. Wait…, is this approach really efficient enough?

  • Do we actually write less code? What we did is just moving those code from test method into those objects.
  • If we go with this approach, every class in our project must override .Equal method no matter what the business requires to do that or not. We may have thousands of classes in a project and this doesn't help to save our efforts.

It’s time to take a further step using of C# Reflection for our unit/integration test by creating a utility method which can help asserting two reference type objects then reuse if for asserting any objects in our project.

public static void AssertTwoObjects<T>(T expected, T actual)
{
    if (expected == null && actual == null)
    {
        Assert.IsTrue(true);
    }
    else if (expected == null && actual != null || expected != null && actual == null)
    {
        Assert.Fail("One of two objects is null");
    } 
    else
        {
            Type type = typeof(T);
            foreach (PropertyInfo property in type.GetProperties())
            {
                object expectedValue = property.GetValue(expected, null);
                object actualValue = property.GetValue(actual, null);
                if (expectedValue == null && actualValue == null)
                    continue;
                Assert.AreEqual(expectedValue, actualValue);
            }
        }
}

The TestMethod should be like this now

[TestMethod]  
public void FooService_SaveASingleFooUser_ReturnExpectedResult()  
{  
   //Arrange  
   FooUser sampleFooUser = Utility.PopulateSampleData<FooUser>();      
   Collection<FooUser> expected = new Collection<FooUser>() { sampleFooUser };  
   //Act  
   Collection<FooUser> actual = FooService.SaveFooUsers(expected);  
   //Assert 
   Utility.AssertTwoObjects<FooUser>(expected[0], actual[0]);
}

We can assert two objects now, there’s no doubt we can do the same with two collections of object. Let’s create a new utility method to assert two collections

public static void AssertTwoCollections<T>(Collection<T> expected, Collection<T> actual)
{
    if (expected == null && actual == null)
        Assert.IsTrue(true);
    else if (expected == null || actual == null)
        Assert.Fail("One of two collections is null while other is not.");
    else
       {
            if (expected.Count != actual.Count)
                Assert.Fail(string.Format(CultureInfo.CurrentCulture, "The number of items of two collections are not equal. Expected: {0} - Actual: {1}", expected.Count, actual.Count));
            for (int i = 0; i < expected.Count; i++)
                AssertTwoObjects(expected[i], actual[i]);
       }
}

Then use it in our tests

[TestMethod]  
public void FooService_SaveFooUsers_ReturnExpectedResult()  
{  
   //Arrange  
   FooUser firstFooUser = Utility.PopulateSampleData<FooUser>();      
   FooUser secondFooUser = Utility.PopulateSampleData<FooUser>();  
   FooUser thirdFooUser = Utility.PopulateSampleData<FooUser>();  
   Collection<FooUser> expected = new Collection<FooUser>() { firstFooUser, secondFooUser, thirdFooUser };  
   //Act  
   Collection<FooUser> actual = FooService.SaveFooUsers(expected);  
   //Assert
   Utility.AssertTwoCollections<FooUser>(expected, actual);
} 

Here are just two simple examples that demonstrate the usage of C# Reflection. If we use it correctly, C# Reflection can show us how incredibly powerful it is in much more complex cases.