How To Use Builder Design Pattern and DataFaker Library for Test Data Generation in Automation Testing
In this tutorial, learn how to use a builder design pattern in Java with a DataFaker library to generate test data for automation testing.
Join the DZone community and get the full member experience.
Join For FreeI bet you might have come across a scenario while automating API/web or mobile applications where, while registering a user, you may be setting the address for checking out a product in the end-to-end user journey in test automation.
So, how do you do that?
Normally, we create a POJO class in Java with the fields required to register a user or to set the address for checking out the product and then set the values in the test using the constructor of the POJO class.
Let’s take a look at an example of registering a user where the following are mandatory fields required to fill in the registration form:
- First Name
- Last Name
- Address
- City
- State
- Country
- Mobile Number
As we need to handle these fields in automation testing we will have to pass on respective values in the fields at the time of executing the tests.
Before Using the Builder Pattern
A POJO class, with the above-mentioned mandatory fields, will be created with the Getter and Setter methods inside that POJO class, and using a constructor values are set in the respective fields.
Check out the code example of RegisterUser class
given below for the representation of what we are discussing.
public class RegisterUser {
private String firstName;
private String lastName;
private String address;
private String city;
private String state;
private String country;
private String mobileNumber;
public RegisterUser (final String firstName, final String lastName, final String address, final String city,
final String state, final String country, final String mobileNumber) {
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
this.city = city;
this.state = state;
this.country = country;
this.mobileNumber = mobileNumber;
}
public String getFirstName () {
return firstName;
}
public void setFirstName (final String firstName) {
this.firstName = firstName;
}
public String getLastName () {
return lastName;
}
public void setLastName (final String lastName) {
this.lastName = lastName;
}
public String getAddress () {
return address;
}
public void setAddress (final String address) {
this.address = address;
}
public String getCity () {
return city;
}
public void setCity (final String city) {
this.city = city;
}
public String getState () {
return state;
}
public void setState (final String state) {
this.state = state;
}
public String getCountry () {
return country;
}
public void setCountry (final String country) {
this.country = country;
}
public String getMobileNumber () {
return mobileNumber;
}
public void setMobileNumber (final String mobileNumber) {
this.mobileNumber = mobileNumber;
}
}
Now, if we want to use this POJO, we would have to create an instance of RegisterUser
class and pass the values in the constructor parameters
as given in the code example below to set the data in the respective fields.
Check out the below example of the Register User
test of how we do it.
public class RegistrationTest {
@Test
public void testRegisterUser () {
RegisterUser registerUser = new RegisterUser ("John", "Doe", "302, Adam Street, 1st Lane", "New Orleans",
"New Jersey", "US", "52145364");
assertEquals (registerUser.getFirstName (), "John");
assertEquals (registerUser.getCountry (), "US");
}
}
There were just seven fields in the example we took for registering the user. However, this would not be the case with every application. There would be some more additional fields required and as the fields keep on increasing every time, we would need to update the POJO class with respective Getter and Setter methods and also update the parameters in the constructor.
Finally, we would need to add the values to those fields so the data could be passed in the actual field required.
Long story short, we would need to update the code even if there is a single new field added, also, it doesn’t look clean to add values as parameters in the tests.
Luckily, the Builder Design Pattern in Java comes to the rescue here.
What Is Builder Design Pattern in Java?
Builder design pattern is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.
Builder Pattern helps us solve the issue of setting the parameters by providing a way to build the objects step by step by providing a method that returns the final object which can be used in the actual tests.
What Is Lombok?
Project Lombok is a Java library that automatically plugs into your editor and builds tools, spicing up your Java. It is an annotation-based Java library that helps in reducing the boilerplate code.
It helps us in writing short and crisp code without having to write the boilerplate code. Bypassing the @Getter
annotation over the class, it automatically generates Getter methods. Similarly, you don’t have to write the code for Setter methods as well, its @Setter
annotation updated over the class automatically generates the Setter methods.
It also has support for using the Builder design pattern so we just need to put the @Builder
annotation above the class and the rest will be taken care of by the Lombok library.
To use Lombok annotations in the project we need to add the following Maven dependency:
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.32</version> <scope>provided</scope> </dependency>
Using the Builder Design Pattern With Lombok
Before we start refactoring the code we have written, let me tell you about the DataFaker library as well as how it helps in generating fake data that can be used for testing. Ideally, in our example, every newly registered user’s data should be unique otherwise we may get a duplicate data error and the test will fail.
Here, the DataFaker library will help us in providing unique data in each test execution thereby helping us with registering a new user with unique data every time the registration test is run.
To use the DataFaker library, we need to add the following Maven dependency to our project.
<!-- https://mvnrepository.com/artifact/net.datafaker/datafaker -->
<dependency>
<groupId>net.datafaker</groupId>
<artifactId>datafaker</artifactId>
<version>2.2.2</version>
</dependency>
Now, let's start refactoring the code. First, we will make the changes to the RegisterUser
class. We would be removing all the Getter and Setter methods and also the constructor and adding the @Getter
and @Builder
annotation tags on the top of the RegisterUser class
.
Here is how the RegisterUser class
looks now after the refactoring
@Getter
@Builder
public class RegisterUserWithBuilder {
private String firstName;
private String lastName;
private String address;
private String city;
private String state;
private String country;
private String mobileNumber;
}
How clean and crisp it looks with that refactoring being done. Multiple lines of code are removed still it will still work in the same fashion as it used to earlier, thanks to Lombok.
We would have to add a new Java class for generating the fake data on runtime using the Builder design pattern. We would be calling this new class the DataBuilder class
.
public class DataBuilder {
private static final Faker FAKER = new Faker();
public static RegisterUserWithBuilder getUserData () {
return RegisterUserWithBuilder.builder ()
.firstName (FAKER.name ()
.firstName ())
.lastName (FAKER.name ()
.lastName ())
.address (FAKER.address ()
.streetAddress ())
.state (FAKER.address ()
.state ())
.city (FAKER.address ()
.city ())
.country (FAKER.address ()
.country ())
.mobileNumber (String.valueOf (FAKER.number ()
.numberBetween (9990000000L, 9999999999L)))
.build ();
}
}
The getUserData()
method will return the test data required for registering the user using the DataFaker library. Notice the builder()
method used after the class name RegisterUserWithBuilder
. It appears because of the @Builder
annotation we have used on the top of the RegisterUserWithBuilder class.
After the builder()
method we have to pass on the variables we have declared in the RegisterUserWithBuilder class
and accordingly, pass the fake data that we need to generate for the respective variables.
RegisterUserWithBuilder.builder ()
.firstName (FAKER.name ()
.firstName ());
The above piece of code will generate a fake first name and set it in the first name variable. Likewise, we have set fake data in all other variables.
Now, let’s move towards how we use these data in the tests. It's very simple, the below code snippet explains it all.
@Test
public void testRegisterUserWithBuilder () {
RegisterUserWithBuilder registerUserWithBuilder = getUserData ();
System.out.println (registerUserWithBuilder.getFirstName ());
System.out.println (registerUserWithBuilder.getLastName ());
System.out.println (registerUserWithBuilder.getAddress ());
System.out.println (registerUserWithBuilder.getCity ());
System.out.println (registerUserWithBuilder.getState ());
System.out.println (registerUserWithBuilder.getCountry ());
System.out.println (registerUserWithBuilder.getMobileNumber ());
}
We just need to call the getUserData()
method while instantiating the RegisterUserWithBuilder class
. Next, we would be calling the Getter methods for the respective variables we declared inside the RegisterUserWithBuilder class
. Remember we had passed the @Getter
annotation on the top of the RegisterUserWithBuilder class
, this actually helps in calling the Getter methods here.
Also, we are not required to pass on multiple data as the constructor parameters for the RegisterUserWithBuilder
class, instead we just need to instantiate the class and call the getUserData()
method!
How easy it is to generate the unique data and pass it on in the tests without having to write multiple lines of boilerplate codes.
Thanks to the Builder design pattern and Lombok!
Running the Test
Let’s run the test and check if the user details get printed in the console. We can see that the fake data is generated successfully in the following screenshot of the test execution.
Conclusion
In this blog, we discussed making use of the builder design pattern in Java with Lombok and DataFaker library to generate fake test data on run time and use it in our automated tests. It would ease the test data generation process by eliminating the need to update the test data before running the tests.
I hope it will help you a lot in reducing the code lines and writing your code in a much cleaner way.
Happy Testing!
Published at DZone with permission of Faisal Khatri. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments