Introduction
In your different type of tests (unit, integration, UI), you often need to verify almost all properties of an object. Usually, it’s too much work to write all asserts for all of them and add a meaningful exception message in case of failure. I will show you how to write a generic validator which can save you a lot of time.
How We Usually Assert Objects
Imagine that we have the following class.
public class ObjectToAssert
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string PoNumber { get; set; }
public decimal Price { get; set; }
public DateTime SkipDateTime { get; set; }
}
We can write code like the one below if we want to assert two instances of the class- the expected and the actual one. The first is defined in our test and the real one can be returned from our DB or some web service.
ObjectToAssert expectedObject = new ObjectToAssert()
{
FirstName = "Anton",
PoNumber = "TestPONumber",
LastName = "Angelov",
Price = 12.3M,
SkipDateTime = new DateTime(1989, 10, 28)
};
ObjectToAssert actualObject = new ObjectToAssert()
{
FirstName = "AntonE",
PoNumber = "TestPONumber",
LastName = "Angelov",
Price = 12.3M,
SkipDateTime = new DateTime(1989, 10, 28)
};
Assert.AreEqual<string>(expectedObject.FirstName, _
actualObject.FirstName, "The first name was not as expected.");
Assert.AreEqual<string>(expectedObject.LastName, _
actualObject.LastName, "The last name was not as expected.");
Assert.AreEqual<string>(expectedObject.PoNumber, _
actualObject.PoNumber, "The PO Number was not as expected.");
Assert.AreEqual<decimal>(expectedObject.Price, _
actualObject.Price, "The price was not as expected.");
DateTimeAssert.Validate(
expectedObject.SkipDateTime,
actualObject.SkipDateTime,
DateTimeDeltaType.Days,
1);
You can see how much code we need to verify every single property.
Note: We use DateTimeAssert class, to verify the dates properties, which is my custom implementation for validation of DateTimes using Delta. You can find more information in my article “Assert DateTime the Right Way MSTest NUnit“.
How to Create Generic Properties Validator
You can use reflection in order to create a better reusable validator.
public class PropertiesValidator<K, T> where T : new() where K : new()
{
private static K instance;
public static K Instance
{
get
{
if (instance == null)
{
instance = new K();
}
return instance;
}
}
public void Validate(T expectedObject, T realObject, params string[] propertiesNotToCompare)
{
PropertyInfo [] properties = realObject.GetType().GetProperties();
foreach ( PropertyInfo currentRealProperty in properties)
{
if (!propertiesNotToCompare.Contains(currentRealProperty.Name))
{
PropertyInfo currentExpectedProperty =
expectedObject.GetType().GetProperty(currentRealProperty.Name);
string exceptionMessage =
string.Format( "The property {0} of class {1}
was not as expected.", currentRealProperty.Name,
currentRealProperty.DeclaringType.Name);
if (currentRealProperty.PropertyType != typeof( DateTime)
&& currentRealProperty.PropertyType != typeof (DateTime ?))
{
Assert .AreEqual(currentExpectedProperty.GetValue(expectedObject, null),
currentRealProperty.GetValue(realObject, null ), exceptionMessage);
}
else
{
DateTimeAssert.Validate(
currentExpectedProperty.GetValue(expectedObject, null) as DateTime?,
currentRealProperty.GetValue(realObject, null) as DateTime ?,
DateTimeDeltaType .Minutes,
5);
}
}
}
}
}
We use singleton pattern to create an instance of the object without the new
keyword in the client code. For the job, we have a static
variable from generic type K
which will be the type of the validator that will derive from our base PropertiesValidator
. The T
type will be the type of the objects to be validated.
The Validate
method accepts 3 parameters the expected object, the actual one and a params array of the names of the properties which should be skipped to be validated.
The core logic of the method is pretty simple. Reflection is used to obtain the properties of the objects. Next we iterate through all and validate them. If the Property type is DateTime
, we use the previously mentioned DateTimeAssert
class.
If you want to create a custom validator in order to add additional asserts or skip the validation of properties, just derive the base PropertiesValidator
class.
public class ObjectToAssertValidator :
PropertiesValidator<ObjectToAssertValidator, ObjectToAssert>
{
public void Validate(ObjectToAssert expected, ObjectToAssert actual)
{
this.Validate(expected, actual, "FirstName");
}
}
The previously six lines of asserts now can be replaced with a single line of code.
ObjectToAssertValidator.Instance.Validate(expectedObject, actualObject);
So Far in the C# Series
1. Implement Copy Paste C# Code
2. MSBuild TCP IP Logger C# Code
3. Windows Registry Read Write C# Code
4. Change .config File at Runtime C# Code
5. Generic Properties Validator C# Code
6. Reduced AutoMapper- Auto-Map Objects 180% Faster
7. 7 New Cool Features in C# 6.0
8. Types Of Code Coverage- Examples In C#
9. MSTest Rerun Failed Tests Through MSTest.exe Wrapper Application
10. Hints For Arranging Usings in Visual Studio Efficiently
11. 19 Must-Know Visual Studio Keyboard Shortcuts – Part 1
12. 19 Must-Know Visual Studio Keyboard Shortcuts – Part 2
13. Specify Assembly References Based On Build Configuration in Visual Studio
14. Top 15 Underutilized Features of .NET
15. Top 15 Underutilized Features of .NET Part 2
16. Neat Tricks for Effortlessly Format Currency in C#
17. Assert DateTime the Right Way MSTest NUnit C# Code
18. Which Works Faster- Null Coalescing Operator or GetValueOrDefault or Conditional Operator
19. Specification-based Test Design Techniques for Enhancing Unit Tests
20. Get Property Names Using Lambda Expressions in C#
21. Top 9 Windows Event Log Tips Using C#
If you enjoy my publications, feel free to SUBSCRIBE
Also, hit these share buttons. Thank you!
Source Code