26 Apr
2008

Test Data Builders Refined

Category:UncategorizedTag: , :

Last year, I blogged about Test Data Builders here and here. I still use them heavily in my unit tests for creating objects with test data. Heck, I also use this pattern for fluent interfaces in production code. Here is a simple example of this approach:

 

   1: public class CustomerBuilder
   2: {
   3:     public String _firstName = "Homer";
   4:     public String _lastName = "Simpson";
   5:         
   6:     public CustomerBuilder WithFirstName(String firstName)
   7:     {
   8:         _firstName = firstName;
   9:         return this;    
  10:     }
  11:  
  12:     public CustomerBuilder WithLastName(String lastName)
  13:     {
  14:         _lastName = lastName;
  15:         return this;
  16:     }
  17:         
  18:     public Customer Build()
  19:     {
  20:         return new Customer(_firstName, _lastName);    
  21:     }
  22: }

This fluent builder class can then be used this way:
   1: Customer customer = new CustomerBuilder()
   2:     .WithFirstName("Homer")
   3:     .WithLastName("Simpson")
   4:     .Build();

A while ago, Greg Young started a series of blog posts on DDDD (Distributed Domain-Driven Design), which I can highly recommend. Make sure to catch up now you still can because I think that he has a lot of stuff coming up, which I’m really looking forward to.

Anyhow, Greg had a couple of posts on fluent builders, which you can read here, here and here. I noticed an interesting approach in the way that the target object is built. Here is an example of this approach:

 

   1: public class CustomerBuilder
   2: {
   3:     public String _firstName = "Homer";
   4:     public String _lastName = "Simpson";
   5:         
   6:     public CustomerBuilder WithFirstName(String firstName)
   7:     {
   8:         _firstName = firstName;
   9:         return this;    
  10:     }
  11:  
  12:     public CustomerBuilder WithLastName(String lastName)
  13:     {
  14:         _lastName = lastName;
  15:         return this;
  16:     }
  17:         
  18:     public Customer Build()
  19:     {
  20:         return new Customer(_firstName, _lastName);    
  21:     }
  22:  
  23:     public static implicit operator Customer(
  24:         CustomerBuilder builder) 
  25:     {  
  26:         return builder.Build()    
  27:     } 
  28: }

which results in the following usage:

 

   1: Customer customer = new CustomerBuilder()
   2:     .WithFirstName("Homer")
   3:     .WithLastName("Simpson");

Adding an implicit cast operator to the builder class makes that its no longer required to explicitly call the Build method. I keep the Build method around for backwards-compatibility reasons or in case I ever need it again (violating YAGNI in the process, I know, I know). I find that adding the implicit cast operator adds to the readability of the fluent interface, don’t you agree?

6 thoughts on “Test Data Builders Refined

Comments are closed.