Stop Hand-Coding Test Data: Generate Java Objects in One Line with Easy Random

This tutorial demonstrates how to use the Easy Random library to automatically generate realistic test data for Java objects, covering basic usage, configuration parameters, field-level customization, and custom randomizers for domain-specific values.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Stop Hand-Coding Test Data: Generate Java Objects in One Line with Easy Random

Introduction

Writing test code often involves more effort in preparing test data than implementing business logic. For simple objects like User this is manageable, but complex structures with dozens of fields, nested objects, and collections quickly turn into repetitive boilerplate. Easy Random solves this by generating random Java object instances automatically.

Easy Random Overview

Easy Random is a library for generating random Java objects (including records). It acts as an "object mother" for the JVM. Given a class Person, a random instance is created with:

EasyRandom er = new EasyRandom();
Person person = er.nextObject(Person.class);

The EasyRandom#nextObject method generates a random instance of any specified type.

Practical Examples

Environment Setup

Environment: Spring Boot 3.5.0

Add the dependency (test scope):

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

Domain Classes

public class Person {
  private Long id;
  private String name;
  private Integer age;
  private Date birth;
  // getters, setters
}

public class Address {
  private String province;
  private String city;
  private String county;
  private String street;
  // getters, setters
}

Quick Start

@Test
public void testRandomPerson() {
  EasyRandom er = new EasyRandom();
  Person person = er.nextObject(Person.class);
  System.err.println(person);
}

Output example:

Person [
  id=-5106534569952410475,
  name=eOMtThyhVNLWUZNRcBaQKxI,
  age=-1188957731,
  birth=Tue Jun 18 18:54:04 CST 2024
]

Default values are often unrealistic (negative age, random strings). Adding an Address field to Person and re-running produces similarly random nested data.

Controlling Data Generation with EasyRandomParameters

EasyRandomParameters

is the main configuration entry point. All parameters apply to every field in the object graph:

EasyRandomParameters parameters = new EasyRandomParameters()
  .seed(123L)                              // fixed seed for reproducible runs
  .objectPoolSize(100)
  .randomizationDepth(3)
  .charset(forName("UTF-8"))              // charset for all strings/chars
  .timeRange(nine, five)                   // time range
  .dateRange(today, tomorrow)              // date range
  .stringLengthRange(5, 50)                // string length bounds
  .collectionSizeRange(1, 10)              // collection size bounds
  .scanClasspathForConcreteTypes(true)     // find implementations for abstract/interface fields
  .overrideDefaultInitialization(false)    // keep default field values
  .ignoreRandomizationErrors(true);

EasyRandom easyRandom = new EasyRandom(parameters);

Field-Specific Customization

Override specific fields using predicates:

@Test
public void testRandomPersonByParameters() {
  EasyRandomParameters parameters = new EasyRandomParameters();
  parameters.overrideDefaultInitialization(false);
  parameters.stringLengthRange(3, 8);
  parameters.randomize(f -> f.getName().equals("age"), new IntegerRangeRandomizer(1, 120));
  EasyRandom er = new EasyRandom(parameters);
  Person person = er.nextObject(Person.class);
  System.err.println(person);
}

Output:

Person [
  id=0,
  name=eOMtTh,
  age=60,
  birth=Tue Jun 18 18:54:04 CST 2024,
  address=Address [
    province=yhVNLWU,
    city=ZNRc,
    county=BaQKxI,
    street=yedUsFw
  ]
]

Exclude a nested field:

parameters.excludeField(FieldPredicates.named("city"));

Custom Randomizer for Domain-Specific Values

Default string generation only produces random letters. Implement AbstractRandomizer<String> for meaningful values:

public class ProvinceRandomizer extends AbstractRandomizer<String> {
  private static final String[] PROVINCES = {
    "北京市", "天津市", "河北省", "山西省", "内蒙古自治区", "辽宁省",
    "吉林省", "黑龙江省", "上海市", "江苏省", "浙江省", "安徽省",
    "福建省", "江西省", "山东省", "河南省", "湖北省", "湖南省",
    "广东省", "广西壮族自治区", "海南省", "重庆市", "四川省", "贵州省", "云南省",
    "西藏自治区", "陕西省", "甘肃省", "青海省", "宁夏回族自治区",
    "新疆维吾尔自治区", "香港特别行政区", "澳门特别行政区", "台湾省"};

  public ProvinceRandomizer() { super(); }
  public ProvinceRandomizer(long seed) { super(seed); }

  @Override
  public String getRandomValue() {
    int index = random.nextInt(PROVINCES.length);
    return PROVINCES[index];
  }
}

Apply it to the province field of Address:

@Test
public void testRandomPersonByParameters() {
  EasyRandomParameters parameters = new EasyRandomParameters();
  // ... other config
  parameters.randomize(named("province").and(inClass(Address.class)), new ProvinceRandomizer());
  EasyRandom er = new EasyRandom(parameters);
  Person person = er.nextObject(Person.class);
  System.err.println(person);
}

Output now includes a real province name:

Person [
  id=0,
  ...
  address=Address [
    province=福建省,
    ...
  ]
]
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaTestingUnit TestingSpring BootTest Data GenerationOpen Source LibraryEasy Random
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.