When writing unit tests, I frequently have an issue with creating objects that contain some test data. One approach is to call the constructor of the class at hand in every test case, like so:
[Test] public void TestCase1() { Customer customer = new Customer("Homer", "Simpson"); // further implementation } [Test] public void TestCase2() { Customer customer = new Customer(null, "Simpson"); // further implementation } [Test] public void TestCase3() { Customer customer = new Customer("Homer", null); // further implementation }
The problem with this approach becomes clear when adding a new argument to the constructor of the Customer class. Now I have to make a change to all tests that create a Customer object.
What I did to overcome this issue, was to use the Object Mother pattern. I created a static class called TestFactory with a bunch of constant fields and methods that create all kinds of objects:
internal static class TestFactory { public const String FirstName = "Homer"; public const String LastName = "Simpson"; private static Customer CreateCustomer(String firstName, String lastName) { return new Customer(firstName, lastName); } public static Customer CreateValidCustomer() { return CreateCustomer(FirstName, LastName); } public static Customer CreateCustomerWithoutFirstName() { return CreateCustomer(null, LastName); } public static Customer CreateCustomerWithoutLastName() { return CreateCustomer(FirstName, null); } }
I didn't really like this approach. For every special case, I needed to add another factory method. I couldn't come up with something better either at the time, so ... until I read this fine article yesterday. Instead of using the Object Mother pattern, the author uses the Builder pattern.
public class CustomerBuilder { public String _firstName = "Homer"; public String _lastName = "Simpson"; public CustomerBuilder WithFirstName(String firstName) { _firstName = firstName; return this; } public CustomerBuilder WithLastName(String lastName) { _lastName = lastName; return this; } public Customer Build() { return new Customer(_firstName, _lastName); } }
The tests itself would look like this:
[Test] public void TestCase1() { Customer customer = new CustomerBuilder().Build(); // further implementation } [Test] public void TestCase2() { Customer customer = new CustomerBuilder() .WithFirstName(null) .Build(); // further implementation } [Test] public void TestCase3() { Customer customer = new CustomerBuilder() .WithLastName(null) .Build(); // further implementation }
Looks pretty neat huh? If you're interested in writing maintainable unit tests, then you should definitely give the article a good read. The examples are written in Java, so I don't know if that has got anything to do with it :-).
