Test Data Builder pattern

Creating test object using they default constructors is very annoying when we have complicated model and variety of different test cases to cover. We can use with help of Creation Class or Object Mother pattern.

With them we can simplify object creation by reducing number of constructors and replace them with creation methods Then we have something like this:

Person person = PersonCreator.createPerson();
Person person = PersonCreator.createPersonWithAccount(Account accont);
Person person = PersonCreator.createPersonWithNameAndAccount(String name, Account account);

But those classes can become cluttered with every variation of object creation method that we use in unit testing. Then its very hard to find right one and we are ending creating new ones for every slightly different object.

Test Data Builder pattern for the rescue.

The main point of the Test Data Builder pattern is to allow to create an object with specific part of his data – the data that are significant to the test. Those data creation should be visible in “given” part of test and avalible for assertion.
The rest of them for which test don’t care should not be visible in test because they distract from actual test case. For this part of object data the builder will provide safe defaults.

This way test using Test Data Builders beacomes more concise and readable:

Person person = new PersonBuilder().build();
Person person = new PersonBuilder().withName("Bob").withoutAccount().build();

Builder source code:

public class PersonBuilder extends Builder{
	private Person person;
	
	public PersonBuilder() {
		person = new Person();
	}
	
	public PersonBuilder withId(String id){
		person.setId(id);
		return this;
	}

	public PersonBuilder withName(String name){
		person.setName(name);
		return this;
	}
	
	public PersonBuilder with(Account account) {
		person.getAccounts().add(account);
		return this;
	}

	public PersonBuilder withoutAccount() {
		person.setAccounts(new ArrayList());
		return this;
	}

	public Person build(){
		return person;
	}
}

With builder we can create some basic predifined builder object to decrease duplication. They can be modified for need of test using “withXXX” and “withoutXXX” methods:

//sample person object fits most of the test cases
Person person = aPerson().build();
//can be easly modified if needed
Person person = aPerson().withoutAccount().build();

For better readability use short version of method names for example:
instead of:

aPerson().withAccount(anAccount().build()).build();

use:

aPerson().with(anAccount().build()).build(); 

Conclusion

For sure builder pattern can reduce duplications in your test code and improve readability. But it needs some additional coding to create builders structure.
If you have complicated model you can use on of automated tools to generate builders code:

For Idea there is refactoring named “replace-constructor-with-builder”. But it uses “set” instead of “with” prefix convention. For more fluent generator you can use
Eclipse: fluent-builder-generator
Idea: Builder Generator

Here you can find example of builder implementation github.com/michal-lipski/mongodb-spring-data/:

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s