In Java6/C#2.0, I have used test data builders many a times for creating objects for tests. Using a builder encapsulates object creation within itself, so that you don't see naked constructor calls at various places in the tests and moreover do the chore of using the correct constructor (if there are multiple) and passing all the required collaborators/initial values in it for the it to be set-up correctly.
In a nutshell, builders shield you:
- when the constructor gets refactored (add/remove parameter), so you don't have to refactor every test
- from adding many flavors of constructors for setting up the object differently.
See http://nat.truemesh.com/archives/000714.html for further information
Lets take the example of a Person object creation in Java:
public class Person {
private String name;
private int age;
private Address homeAddress;
}
public class Address {
private string house;
private string street;
private string state;
private string country;
}
Person person = new PersonBuilder()
.withName("Some Name")
.withAge(60)
.withHomeAddress(new AddressBuilder()
.withHouse("#45")
.withStreet("Some Street")
.build())
.build();
Here are the corresponding builders for the Person and the Address class.
public class PersonBuilder {
private String name;
private String age;
private Address homeAddress;
public PersonBuilder withName(String name) {
this.name = name;
return this;
}
public PersonBuilder withAge(String age) {
this.age = age;
return this;
}
public PersonBuilder withHomeAddress(Address homeAddress) {
this. homeAddress = homeAddress;
return this;
}
public Person build() {
Person person = new Person(name);
person.setAge(age);
person.setHomeAddress(homeAddress);
return person;
}
}
Languages like Groovy, C# provide constructs for initializing objects differently. This in my opinion alleviates the need for using a builder pattern to create objects that are required with different set-up values. For example, the above can in Groovy, be written in atleast 3 different ways, choose whichever on your personal taste:
class Person {
string name
int age
Address homeAddress
}
class Address {
string house
string street
string state
string country
}
Here are different ways in which one can initialize object in Groovy (very flexible)
//I. Creating Object using Named Parameters
def person = new Person(name:'Dhaval Dalal',
age:60,
homeAddress:new Address(house:'#45',
street:'Some St.',
state:'NY',
country:'US'))
println "Person From Object Initializer = ${person}"
//II. Creating Person using the with or the identity closure
def address = new Address()
address.with {
house = '#45',
street = 'Bergemont',
state = 'NY',
country = 'US'
}
def person = new Person()
person.identity {
name = 'Dhaval Dalal'
age = 60
homeAddress = address
}
println "Person from with/identity closure = ${person}"
//IIIa. Creating Object from Map
Person person = [name:'Dhaval Dalal',
age:60,
homeAddress:[house:'#45',
street:'Some St.',
state:'NY',
country:'US'] //Implicit type conversion for address
]
println "Person From Map = ${person}"
//IIIb. Creating Object from Map (using operator 'as')
def person = [name:'Dhaval Dalal',
age:60,
homeAddress:[house:'#45',
street:'Some St.',
state:'NY',
country:'US']
] as Person
println "Person From Map = ${person}"
Here is the equivalent, C# 3.0 Code:
new Person()
{
Name = "Dhaval Dalal",
Age = 60
}
new Person()
{
Name = "Dhaval Dalal",
Age = 60,
HomeAddress = new Address()
{
House = "#45",
Street = "Some Street",
State = "Some State",
Country = "Some Country"
}
}
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
public Address HomeAddress { get; set; }
}
public class Address
{
public string House { get; set; }
public string Street { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
I'd say that Groovy offers more alternative to construct objects as compared to C#.
If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it: