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

  • 7 Awesome Libraries for Java Unit and Integration Testing
  • Improving Java Code Security
  • Defensive Programming With Klojang Check
  • Practical Use of Weak Symbols

Trending

  • Mastering Advanced Traffic Management in Multi-Cloud Kubernetes: Scaling With Multiple Istio Ingress Gateways
  • How to Format Articles for DZone
  • Develop a Reverse Proxy With Caching in Go
  • Scalable System Design: Core Concepts for Building Reliable Software
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Improving Unit Test Maintainability

Improving Unit Test Maintainability

Creating unit tests could be painful sometimes. Let's see how to improve the maintainability of unit tests with EasyRandom.

By 
Francisco Moreno user avatar
Francisco Moreno
DZone Core CORE ·
Oct. 20, 23 · Tutorial
Likes (19)
Comment
Save
Tweet
Share
8.8K Views

Join the DZone community and get the full member experience.

Join For Free

When doing unit tests, you have probably found yourself in the situation of having to create objects over and over again. To do this, you must call the class constructor with the corresponding parameters. So far, nothing unusual, but most probably, there have been times when the values of some of these fields were irrelevant for testing or when you had to create nested "dummy" objects simply because they were mandatory in the constructor.

All this has probably generated some frustration at some point and made you question whether you were doing it right or not; if that is really the way to do unit tests, then it would not be worth the effort.

That is to say, typically, a test must have a clear objective. Therefore, it is expected that within the SUT (system under test) there are fields that really are the object of the test and, on the other hand, others are irrelevant.

Let's take an example. Let's suppose that we have the class "Person" with the fields Name, Email, and Age. On the other hand, we want to do the unit tests of a service that, receiving a Person object, tells us if this one can travel for free by bus or not. We know that this calculation only depends on the age. Children under 14 years old travel for free. Therefore, in this case, the Name and Email fields are irrelevant.

In this example, creating Person objects would not involve too much effort, but let's suppose that the fields of the Person class grow or nested objects start appearing: Address, Relatives (List of People), Phone List, etc. Now, there are several issues to consider:

  • It is more laborious to create the objects.
  • What happens when the constructor or the fields of the class change?
  • When there are lists of objects, how many objects should I create?
  • What values should I assign to the fields that do not influence the test?
  • Is it good if the values are always the same, without any variability?

Two well-known design patterns are usually used to solve this situation: Object Mother and Builder. In both cases, the idea is to have "helpers" that facilitate the creation of objects with the characteristics we need.

Both approaches are widespread, are adequate, and favor the maintainability of the tests. However, they still do not resolve some issues:

  • When changing the constructors, the code will stop compiling even if they are fields that do not affect the tests.
  • When new fields appear, we must update the code that generates the objects for testing.
  • Generating nested objects is still laborious.
  • Mandatory and unused fields are hard coded and assigned by default, so the tests have no variability.

One of the Java libraries that can solve these problems is "EasyRandom." Next, we will see details of its operation.

What is EasyRandom?

EasyRandom is a Java library that facilitates the generation of random data for unit and integration testing. The idea behind EasyRandom is to provide a simple way to create objects with random values that can be used in tests. Instead of manually defining values for each class attribute in each test, EasyRandom automates this process, automatically generating random data for each attribute.

This library handles primitive data types, custom classes, collections, and other types of objects. It can also be configured to respect specific rules and data generation restrictions, making it quite flexible.

Here is a basic example of how EasyRandom can be used to generate a random object:

Java
 
public class EasyRandomExample {
    public static void main(String[] args) {

        EasyRandom easyRandom = new EasyRandom();

        Person randomPerson = easyRandom.nextObject(Person.class);
        System.out.println(randomPerson);
    }
}


In this example, Person is a dummy class, and easyRandom.nextObject(Person.class) generates an instance of Person with random values for its attributes.

As can be seen, the generation of these objects does not depend on the class constructor, so the test code will continue to compile, even if there are changes in the SUT. This would solve one of the biggest problems in maintaining an automatic test suite.

Why Is It Interesting?

Using the EasyRandom library for testing your applications has several advantages:

  1. Simplified random data generation: It automates generating random data for your objects, saving you from writing repetitive code for each test.
  2. Facilitates unit and integration testing: By automatically generating test objects, you can focus on testing the code's behavior instead of worrying about manually creating test data.
  3. Data customization: Although it generates random data by default, EasyRandom also allows you to customize certain fields or attributes if necessary, allowing you to adjust the generation according to your needs.
  4. Reduced human error: Manual generation of test data can lead to errors, especially when dealing with many fields and combinations. EasyRandom helps minimize human errors by generating consistent random data.
  5. Simplified maintenance: If your class requirements change (new fields, types, etc.), you do not need to manually update your test data, as EasyRandom will generate them automatically.
  6. Improved readability: Using EasyRandom makes your tests cleaner and more readable since you do not need to define test values explicitly in each case.
  7. Faster test development: By reducing the time spent creating test objects, you can develop tests faster and more effectively.
  8. Ease of use: Adding this library to our Java projects is practically immediate, and it is extremely easy to use.

Where Can You Apply It?

This library will allow us to simplify the creation of objects for our unit tests, but it can also be of great help when we need to generate a set of test data. This can be achieved by using the DTOs of our application and generating random objects to later dump them into a database or file. Where it is not recommended: this library may not be worthwhile in projects where object generation is not complex or where we need precise control over all the fields of the objects involved in the test.

How To Use EasyRandom

Let's see EasyRandom in action with a real example, environment used, and prerequisites.

Prerequisites

  • Java 8+
  • Maven or Gradle

Initial Setup

Inside our project, we must add a new dependency. The pom.xml file would look like this:

XML
 
<dependency>
    <groupId>org.jeasy</groupId>
    <artifactId>easy-random-core</artifactId>
    <version>5.0.0</version>
</dependency>


Basic Use Case

The most basic use case has already been seen before. In this example, values are assigned to the fields of the person class in a completely random way. Obviously, when testing, we will need to have control over some specific fields. Let's see this as an example. Recall that EasyRandom can also be used with primitive types. Therefore, our example could look like this.

Java
 
public class PersonServiceTest {
    private final EasyRandom easyRandom = new EasyRandom();
    private final PersonService personService = new PersonService();

    @Test
    public void testIsAdult() {
        Person adultPerson = easyRandom.nextObject(Person.class);
   
        adultPerson.setAge(18 + easyRandom.nextInt(80));

        assertTrue(personService.isAdult(adultPerson));
    }

    @Test
    public void testIsNotAdult() {
        Person minorPerson = easyRandom.nextObject(Person.class);

        minorPerson.setAge(easyRandom.nextInt(17));

        assertFalse(personService.isAdult(minorPerson));
    }
}


As we can see, this way of generating test objects protects us from changes in the "Person" class and allows us to focus only on the field we are interested in.

We can also use this library to generate lists of random objects.

Java
 
@Test
void generateObjectsList() {
    EasyRandom generator = new EasyRandom();

  //Generamos una lista de 5 Personas
    List<Person> persons = generator.objects(Person.class, 5)
        .collect(Collectors.toList());

    assertEquals(5, persons.size());
}


This test, in itself, is not very useful. It is simply to demonstrate the ability to generate lists, which could be used to dump data into a database. 

Generation of Parameterized Data

Let's see now how to use this library to have more precise control in generating the object itself. This can be done by parameterization.

Set the value of a field. Let's imagine the case that for our tests, we want to keep certain values constant (an ID, a name, an address, etc.) To achieve this, we would have to configure the initialization of objects using "EasyRandomParameters" and locate the parameters by their name.

Let's see how:

Java
 
EasyRandomParameters params = new EasyRandomParameters();

// Asignar un valor al campo por medio de una función lamba
params.randomize(named("age"),()-> 5);

EasyRandom easyRandom = new EasyRandom(params);

// El objeto tendrá siempre una edad de 5
Person person = easyRandom.nextObject(Person.class);


Of course, the same could be done with collections or complex objects.

Let's suppose that our class Person, contains an Address class inside and that, in addition, we want to generate a list of two persons.

Let's see a more complete example:

Java
 
EasyRandomParameters parameters = new EasyRandomParameters()
                .randomize(Address.class, () -> new Address("Random St.", "Random City"))

EasyRandom easyRandom = new EasyRandom(parameters);
return Arrays.asList(
        easyRandom.nextObject(Person.class),
        easyRandom.nextObject(Person.class)
);


Suppose now that a person can have several addresses. This would mean the "Address" field will be a list inside the "Person" class.

With this library, we can also make our collections have a variable size. This is something that we can also do using parameters.

Java
 
EasyRandomParameters parameters = new EasyRandomParameters()
               .randomize(Address.class, () -> new Address("Random St.", "Random City"))
    .collectionSizeRange(2, 10); 

EasyRandom easyRandom = new EasyRandom(parameters);

// El objeto tendrá una lista de entre 2 y 10 direcciones
Person person = easyRandom.nextObject(Person.class);


Setting Pseudo-Random Fields

As we have seen, setting values is quite simple and straightforward. But what if we want to control the randomness of the data? We want to generate random names of people, but still names and not just strings of unconnected characters. This same need is perhaps clearer when we are interested in having randomness in fields such as email, phone number, ID number, card number, city name, etc.

For this purpose, it is useful to use other data generation libraries. One of the best-known is Faker.

Combining both libraries, we could get a code like this:

Java
 
EasyRandomParameters params = new EasyRandomParameters();
//Generar número entre 0 y 17
params.randomize(named("age"), () -> Faker.instance().number().numberBetween(0, 17));

// Generar nombre "reales" aleatorios
params.randomize(named("name"), () -> Faker.instance().name().fullName());

EasyRandom easyRandom = new EasyRandom(params);

Person person = easyRandom.nextObject(Person.class);


There are a multitude of parameters that allow us to control the generation of objects. 

Closing

EasyRandom is a library that should be part of your backpack if you develop unit tests, as it helps maintain unit tests. In addition, and although it may seem strange, establishing some controlled randomness in tests may not be a bad thing. In a way, it is a way to generate new test cases automatically and will increase the probability of finding bugs in code.

Integration testing Library Maintainability Java (programming language) unit test

Opinions expressed by DZone contributors are their own.

Related

  • 7 Awesome Libraries for Java Unit and Integration Testing
  • Improving Java Code Security
  • Defensive Programming With Klojang Check
  • Practical Use of Weak Symbols

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!