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
Please enter at least three characters to search
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

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

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

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

  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • Reliability Models and Metrics for Test Engineering
  • Architecture Patterns : Data-Driven Testing
  • The Power of Data-Driven Testing: A Deep Dive into Jakarta Persistence Specifications and NoSQL

Trending

  • Scaling Mobile App Performance: How We Cut Screen Load Time From 8s to 2s
  • How to Build Scalable Mobile Apps With React Native: A Step-by-Step Guide
  • Artificial Intelligence, Real Consequences: Balancing Good vs Evil AI [Infographic]
  • Kubeflow: Driving Scalable and Intelligent Machine Learning Systems
  1. DZone
  2. Data Engineering
  3. Data
  4. Another Data POJO Builder for Tests

Another Data POJO Builder for Tests

Learn how to use Builder4Test, a data POJO build for automated Java tests.

By 
Adolfo Custidiano user avatar
Adolfo Custidiano
·
Nov. 20, 18 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
14.8K Views

Join the DZone community and get the full member experience.

Join For Free

If you feel that your tests look like a big Jenga tower you might find this article interesting. I know what you are thinking, how is another builder library going to help me? Moreover, some people might say it is a total overkill or there is no need for it (and they might be right) because every project is different, but there is something that all projects should have: good code quality. Not only for the production code but for the tests. In my experience, I have come to the conclusion that this is our weakest point, not because we are not willing to write good tests but because modifying and maintaining existing tests has been a difficult part of our task, especially when we are trying to revert this by re-writing it. When you read a test you can notice a few clues that lead to an inevitable refactor of it, for instance:

  • When you need to scroll several times to finish reading one scenario.
  • Where you don’t need to scroll so much but it has a lot of private methods, most of them doing very similar things and the only difference are a few parameters.
  • Where you use production builders code to construct your data POJO but it is still difficult to understand and even to modify one simple value derives in a copy and paste/adding another private method with different set of parameters to build the POJO.
  • And the complexity could go higher if you are building a complex tree of objects.
  • When you have to mutate your object after it has been constructed.

Most of our tests could be simplified a lot by using data test builders. I have tried a few libraries in the past but none of them seem to resolve the majority of the problems. The library that we are going to explore here might fulfil your expectations and scenarios that you have in mind. Feel free to raise issues on github and PR’s are always welcome!

So let’s see some code! Right below we have a complex POJO that we want to build:

public class Order {

    private List<Item> items;
    private Customer customer;
    private Vendor vendor;

    private class Item {
        private UUID id;
        private Product product;
        private int quantity;
        private double price;
    }

    private class Product {
        private String name;
        private String description;
    }

    private class Customer {
        String firstName;
        String lastNAme;
        Address address;
    }

    private class Vendor {
        String name;
        Address address;
    }

    private class Address {
        String street;
        String number;
        String postCode;
    }
}

Now for simplicity let’s assume that we have the traditional builders for each entity. In order to use these builders in your test you might have to create a class that contains a method similar to the one below:

public static Order buildDefaultOrder() {
    return Order.builder()
            .withItems(Item.builder()
                    .withId(UUID.randomUUID())
                    .withProduct(Product.builder()
                            .withName("test")
                            .withDescription("value")
                            .build())
                    .withQuantity(3)
                    .withPrice(2.2d)
                    .build())
            .withCustomer(Customer.builder()
                    .withFirstName("Alan")
                    .withLastName("Joe")
                    .withAddress(Address.builder().build())
                    .build())
            .withVendor(Vendor.builder().build())
            .build();
}

This doesn’t look that bad, doesn’t it? It is easy to read, but what if I need to override some of those default values? Someone could argue that it can be achieved by mutating the object like this:

public void buildOrder(String firstName) {
    Order order = buildDefaultOrder();
    order.getCustomer().setFirstName(firstName);
}

and now imagine the code if I have to update only the LastName of the customer or both at the same time. By following the same line of thinking I would have something like this:

public void buildOrderWithLastName(String lastName) {
    Order order = buildDefaultOrder();
    order.getCustomer().setLastName(lastName);
}

public void buildOrderWithFirstNameAndLastName(String firstName, String lastName) {
    Order order = buildDefaultOrder();
    order.getCustomer().setFistName(firstName);
    order.getCustomer().setLastName(lastName);
}

As you might have realised by now, the solution scales up in that way by adding methods per combination of data and compromising the immutability of our domain objects for the sake of our tests, which is not good at all.

Solution

Use Builder4Test! The library provides an intuitive DSL that also scales up in a very nice and simple way. You won’t have to add methods and no need to sacrifice the immutability of your domain objects.

How does it look? Let’s dig a little bit more and see how it works.

public static Field<String> firstName = new Field<>();
public static Field<String> lastName = new Field<>();

public static Creator<Order> orderCreator = (lookUp) ->
    Order.builder()
            .withItems(Item.builder()
                    .withId(UUID.randomUUID())
                    .withProduct(Product.builder()
                            .withName("test")
                            .withDescription("value")
                            .build())
                    .withQuantity(3)
                    .withPrice(2.2d)
                    .build())
            .withCustomer(Customer.builder()
                    .withFirstName(lookUp.get(firstName, "Alan")
                    .withLastName(lookUp.get(lastName, "Joe")
                    .withAddress(Address.builder().build())
                    .build())
            .withVendor(Vendor.builder().build())
            .build()
}

Builder4Test DSL will require you to implement a Creator Interface, to define how to build the object and which fields you want to override, as well as what will be the default values for those in case you don’t want to override it.

Once you have your creator, you will consume it by Builder4Test DSL like this.

@Test
public void testbuildOrderWithFirstName() {
    Builder.build()
            .entity(orderCreator)
            .override(firstName, "Thomas")
            .get();
}

@Test
public void testbuildOrderWithLastName() {
    Builder.build()
            .entity(orderCreator)
            .override(lastName, "Eddison")
            .get();
}

@Test
public void testbuildOrderWithFirstNameAndLastName() {
    Builder.build()
            .entity(orderCreator)
            .override(lastName, "Eddison")
            .override(firstName, "Thomas")
            .get();
}

Conclusion

One of the major benefits that you can get from Builder4Test:

  • The tests will become more maintainable and flexible for eventual new requirements without affecting other tests,
  • No need to add methods for each combination of data that you need to modify.
  • Keep your objects immutable!

Builder4Test offers many other cool features like random generation of data. Please check the demo project to find more details about how to use the library.

Feel free to make contributions to improve it by checking Builder4Test Github project.

Testing Data (computing)

Opinions expressed by DZone contributors are their own.

Related

  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • Reliability Models and Metrics for Test Engineering
  • Architecture Patterns : Data-Driven Testing
  • The Power of Data-Driven Testing: A Deep Dive into Jakarta Persistence Specifications and NoSQL

Partner Resources

×

Comments
Oops! Something Went Wrong

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:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!