Handling Complex Fake or Test Data When Unit Testing-Builder Pattern

The data supporting the unit tests you are creating may have classes that contain other classes as properties. Here we have a Person class that contains an Address class

public class Person{
	public string FirstName {get;set;} 
	public string LastName {get;set;}
	public Address Address{get;set;}
}

public class Address{
	public string Address1{get;set;}
	public string PostCode{get;set;}
	public string Country{get;set;}
}

There are a number of possible scenarios to be unit tested, i.e. If the address is missing or invalid or missing person details. For each unit test the test objects will need to be created which could easily result in duplicate or just tedious typing. For example objects similar to the one below may need to be created with slightly different data for each test.

var person = new Person{
	FirstName="Joe",
	LastName="Bloggs",
	Address=new Address{
		Address1="1 The Grove",
		PostCode="PembroVille",
		Country="United Kingdom"	
	}
};

A real life scenario could involve more complex classes than this example resulting in more tedious duplication. One useful trick is to create a builder class to easily build objects that cater for different test scenarios. In this builder class you can configure the data for each different positive and negative test with the advantages of configure once, reusable code.
Below is a PersonBuilder class which aids in building a Person object with different data relevant to the tests being performed.

public class PersonBuilder
{
    private Person _person = new Person();

    public Person Build(){
        // Set standard default values for properties here if needed
        return _person;
    }

    public PersonBuilder WithValidDetails()
    {
        _person.FirstName="Joe";
        _person.LastName="Bloggs";
        return this;
    }

    public PersonBuilder WithValidAddress()
    {
        _person.Address=new Address{
            Address1="1 The Grove",
            PostCode="PembroVille",
            Country="United Kingdom"
        };
        return this;
    }
	
    public PersonBuilder WithInValidAddress()
    {
        _person.Address=null;
        return this;
    }
}

I can build an empty Person

	var person = new PersonBuilder().WithValidDetails().Build();

A Person with valid details and an valid address

var person = new PersonBuilder().WithValidDetails().WithValidAddress().Build();

This is a somewhat simplified example which would work easily well with complex classes.

String Object Extension Methods

The C# Programming Guide describes extension methods as,

Extension methods enable you to “add” methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. For client code written in C# and Visual Basic, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.

Below are a couple of examples that extend the string object.  The first method reverses a string, functionality which appears to be missing from C#

public static String Reverse(this String oldString)
{
    StringBuilder newString = new StringBuilder();
    for (int i = oldString.Length - 1; i >= 0; i--)
    {
        newString.Append(oldString[i]);
    }
    return newString.ToString();
}

The next method uses regular expressions to replace characters in a string.

public static String Replace(this string originalString, string oldValue,
         string newValue, bool ignoreCase = false)
{
    Regex regEx = new Regex(oldValue,
        RegexOptions.IgnoreCase | RegexOptions.Multiline);
    if (ignoreCase)
    {
        regEx = new Regex(oldValue, RegexOptions.Multiline);
    }
    return regEx.Replace(originalString, newValue);
}

The type of the first parameter, which has the this keyword before it, defines what type of object is being extended. Normal this. notation can be used to reference properties of the extended object  from within the method.

To those of you familiar with SOLID principles the above description of extension methods will sound a lot like the Open-Closed principle (OCP).  This principle states that objects should be extendable without recompiling the application, modifying the original object or changing the existing behaviour of the object.  I agree to some degree that extensions methods do follow the OCP, though there is more to the principle than extending an object with static methods.  For now I will leave it to you to investigate  OCP further.