DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Projections/DTOs in Spring Data R2DBC
  • Testcontainers With Kotlin and Spring Data R2DBC
  • Using Barcodes in iText 7
  • The Cypress Edge: Next-Level Testing Strategies for React Developers

Trending

  • While Performing Dependency Selection, I Avoid the Loss Of Sleep From Node.js Libraries' Dangers
  • Solid Testing Strategies for Salesforce Releases
  • Is Agile Right for Every Project? When To Use It and When To Avoid It
  • The 4 R’s of Pipeline Reliability: Designing Data Systems That Last
  1. DZone
  2. Data Engineering
  3. Data
  4. The Builder Pattern in Java: Guide to Test Data Generation

The Builder Pattern in Java: Guide to Test Data Generation

In this tutorial, learn how to use the Builder pattern in Java with a Datafaker library to generate test data for automated testing.

By 
Faisal Khatri user avatar
Faisal Khatri
DZone Core CORE ·
Jun. 15, 24 · Tutorial
Likes (8)
Comment
Save
Tweet
Share
13.3K Views

Join the DZone community and get the full member experience.

Join For Free

While automating API, web, or mobile applications that require user registration for automated testing, you typically set the address for a product in the end-to-end user journey.

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. Then, we set the values in the test using the constructor of the POJO class.

Let’s take a look at an example scenario where registering a user incorporates the following mandatory fields to fill in the registration form:

  1. First Name
  2. Last Name
  3. Address
  4. City
  5. State
  6. Country
  7. Mobile Number

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 Design Pattern

A POJO class, with the above-mentioned mandatory fields, will be created with the Getter and Setter methods inside that POJO class,  using the constructor value set in the respective fields.

Check out the code example of RegisterUser class below:

Java
 
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 following example of the Register User test:

Java
 
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 additional fields required, and as the fields increase each time, we would need to update the POJO class with respective Getter and Setter methods as well as update the parameters in the constructor. Finally, we would need to add the values to those fields so that the data is passed in the required field.

Long story short, we would need to update the code even if there is a single new field added. Additionally, it doesn’t look clean to add values as parameters in the tests. Luckily, the Builder pattern in Java comes to the rescue here. 

Find the following example code on GitHub here. 

What Is the Builder Pattern in Java?

The Builder design pattern is a creational pattern in Java that lets you construct complex objects step by step. This pattern allows you to produce different types and representations of an object using the same construction code. 

The Builder pattern in Java also helps us solve the issue of setting parameters by providing a way to build the objects step by step, providing a method that returns a 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 code. It is an annotation-based Java library that helps reduce boilerplate code.

Project Lombok also assists us in:

  • Writing short, crisp code without having to write boilerplate code. 
  • Bypassing the @Getterannotation over the class, it automatically generates Getter methods.
  • Similarly, you don’t have to write the code for Setter methods as its @Setterannotation updated over the class automatically generates the Setter methods.

Project Lombok supports the Builder pattern in Java, so we just need to put the @Builderannotation above the class — and the rest is 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 our code, let's discuss the Datafaker library as well as how it helps generate 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 for each test execution, thereby helping us to register 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:

XML
 
<!-- 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 changes to the RegisterUser class. We would be removing all Getter, Setter, and constructor methods, adding the @Getter and @Builder annotation tags on the top of the RegisterUser class.

Here is how the RegisterUser class looks after the refactoring:

Java
 
@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;
}


Check out how clean and crisp it looks with that refactoring done! Multiple lines of code are removed, yet it still works in the same fashion as shown previously, thanks to Lombok.

We would need to add a new Java class for generating the fake data on runtime using the Builder design pattern, thus calling this the DataBuilder class.

Java
 
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 used on top of the RegisterUserWithBuilder class.

After the builder() method, we need to pass the variables declared in the RegisterUserWithBuilder class as well as the fake data needed for its respective variables.

Java
 
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 quite simple: the below code snippet demonstrates it all:

Java
 
    @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 call the Getter methods for the respective variables we declared inside the RegisterUserWithBuilder class. 

Remember: We passed the @Getter annotation on 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!

Thanks to the Builder design pattern and Project Lombok, it is quite easy to generate the unique data for automated tests without having to write multiple lines of boilerplate code!

Running the Test

Let’s run the test and check if the user details are printed in the console:

Builder design pattern in Java for test automation

Test data generation example via the Builder pattern and Project Lombok

Hooray! We can see that the fake data is generated successfully in the screenshot above of the test execution.

Conclusion

In this article, we discussed making use of the Builder design pattern in Java with Project Lombok and the Datafaker library to generate test data at runtime and use it in our automated tests. This eases the test data generation process by eliminating the need to update the test data before running each test.

I hope this tutorial helps in reducing your lines of code and writing cleaner code.

Happy testing!

Builder pattern Data (computing) Java (programming language) Testing

Published at DZone with permission of Faisal Khatri. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Projections/DTOs in Spring Data R2DBC
  • Testcontainers With Kotlin and Spring Data R2DBC
  • Using Barcodes in iText 7
  • The Cypress Edge: Next-Level Testing Strategies for React Developers

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: