How to Utilize Java 'Records' in Test Automation

Rakesh VardanRakesh Vardan
5 min read

Introduction

Writing clean, maintainable test automation code is crucial for ensuring long-term project success. One of the challenges test engineers face is managing the repetitive, boilerplate code needed for data models in test cases. Fortunately, Java 14 introduced a preview feature called 'Records', which was finalized in Java 16. Records provide a succinct and expressive way to define immutable data carriers, significantly reducing the amount of boilerplate code.

In this blog, we’ll explore how Java Records can enhance your test automation, making your code more concise, readable, and maintainable. We will also compare Records with Lombok, a popular library used for reducing boilerplate code in earlier Java versions.

For different examples of using Java Records with real-time APIs in test automation, you can check out my GitHub project here.

Understanding Java Records

Java Records are a special kind of class in Java designed to act as immutable data carriers. They can be thought of as nominal tuples, containing immutable fields where the compiler automatically generates methods like equals(), hashCode(), toString(), and accessors. This makes Records particularly suited for use cases where you need to store and retrieve data without much additional logic.

Key Features of Java Records:

  • Immutability: Fields in Records are final, ensuring that the data can't be changed once created.

  • Generated Methods: The Java compiler automatically provides implementations for equals(), hashCode(), and toString() methods.

  • Accessor Methods: Instead of traditional getters, Records use accessor methods that match the field names.

Example of Java Record

Here’s a simple example of a User record:

public record User(String username, String password) {}

This one line of code is equivalent to writing a traditional class with private final fields, a constructor, and several utility methods like equals() and hashCode().

Why Use Java Records in Test Automation?

Test automation often involves setting up test data models, such as user credentials, API requests, or database entities. These models tend to be simple data holders without much business logic, making them perfect candidates for Records.

Benefits of Java Records in Test Automation:

  • Reduced Boilerplate: Simplifies the code by auto-generating common methods, eliminating the need for manual coding of accessors and other methods.

  • Improved Readability: Compact syntax helps focus on the logic of the test rather than unnecessary class definitions.

  • Ease of Maintenance: Less code means fewer points of failure and easier maintenance over time.

Example: Simplifying Test Code

Let’s consider a test scenario for verifying login functionality. Here’s how you might implement it without using Records:

Without Records

public class User {
    private final String username;
    private final String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}

And use it in a test like this:

@Test
public void testLogin() {
    User user = new User("testuser", "testpassword");
    loginPage.login(user.getUsername(), user.getPassword());
    assertTrue(dashboardPage.isLoggedIn());
}

With Records

By using Records, the code becomes much more concise:

public record User(String username, String password) {}

And use it in a test like this:

@Test
public void testLogin() {
    User user = new User("testuser", "testpassword");
    loginPage.login(user.username(), user.password());
    assertTrue(dashboardPage.isLoggedIn());
}

In this case, the test logic remains the same, but the code is simplified, making it easier to read and maintain.

Real-World Example: Testing an E-commerce Application

Consider a more complex test scenario in which we’re testing an e-commerce application. Here, we need to represent a Order containing an order ID, user details, and a list of items.

Without Records

Without using Records (or Lombok), the Order class might look like this:

public class Order {
    private final String id;
    private final User user;
    private final List<Item> items;

    public Order(String id, User user, List<Item> items) {
        this.id = id;
        this.user = user;
        this.items = items;
    }

    public String getId() {
        return id;
    }

    public User getUser() {
        return user;
    }

    public List<Item> getItems() {
        return items;
    }
}

With Records

Using Records simplifies this model dramatically:

public record Order(String id, User user, List<Item> items) {}

In a test, you could then represent and work with Order like this:

@Test
public void testOrderProcessing() {
    User user = new User("testuser", "testpassword");
    List<Item> items = Arrays.asList(new Item("item1", 2), new Item("item2", 1));
    Order order = new Order("order1", user, items);

    orderPage.placeOrder(order);
    assertTrue(orderPage.isOrderPlaced(order.id()));
}

Comparing Java Records with Lombok

Before Java Records were introduced, developers often turned to Lombok to reduce boilerplate code. Lombok provides annotations like @Data, @Getter, and @Setter, which automatically generates common methods at compile time. However, Records, being a built-in language feature, come with their advantages and trade-offs.

Key Differences:

  • Java Version:

    • Records: Available from Java 16 onward.

    • Lombok: Compatible with older Java versions.

  • Immutability:

    • Records: Fields are inherently final, ensuring immutability.

    • Lombok: Can generate mutable objects unless explicitly marked with @Value for immutability.

  • Dependencies:

    • Records: Native to Java—no external dependencies.

    • Lombok: Requires adding an external library to your project.

  • Tooling Support:

    • Records: Supported by most modern IDEs and tools since they are part of the core Java language.

    • Lombok: Some IDEs may have compatibility issues due to Lombok's bytecode manipulation.

When to Use Records vs. Lombok:

  • Use Records if:

    • You're using Java 16 or later.

    • You need simple, immutable data carriers with minimal custom behaviour.

  • Use Lombok if:

    • You’re working with older Java versions.

    • You need mutable objects or more flexibility in the generated code.

Conclusion

Java Records are a powerful tool for test automation, especially when working with simple, immutable data models. They reduce boilerplate code, enhance readability, and make tests easier to maintain. While Lombok remains a great option for those using earlier Java versions or needing additional flexibility, Records provides a cleaner, more efficient approach for modern Java applications.

When writing test automation in Java 16 or later, consider using Records to simplify your data model representations and improve the overall maintainability of your codebase.

0
Subscribe to my newsletter

Read articles from Rakesh Vardan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Rakesh Vardan
Rakesh Vardan

I am a Software Development Engineer in Test (SDET) specializing in CI/CD processes, with a strong background in UI and API test automation. My expertise lies in designing robust testing frameworks that integrate seamlessly with CI/CD workflows, guaranteeing software quality and reliability.