1. Overview
In this tutorial, we’ll show how to generate Java objects with the EasyRandom library.
2. EasyRandom
In some cases, we need a set of model objects that we’ll use for testing purposes. Or, we’d like to populate our test database with some data we’re going to make use of. Then, maybe we’d want to have collections of dummy DTOs to send back to our client.
Setting up one, two or a few such objects might be easy if they’re not complex. Yet, there might be a case when we’d need hundreds of them immediately, without getting our hands dirty with manual setup.
Here’s where EasyRandom steps in. EasyRandom is a library that’s easy to use, requires little to nothing set up and just by passing the class type, it’s gonna instantiate whole object graphs for us.
Let’s see how easy it is.
3. Objects Generation
The two most important classes in the library are:
- EasyRandom that’s going to generate the objects, and
- EasyRandomParameters that allows us to configure the generation process and make it more predictable.
3.1. Single Object
Our first example generates simple random Person object that has no nested objects, no collections, just an Integer, and two Strings.
Let’s generate one instance of our object using nextObject(Class<T> t):
@Test void givenDefaultConfiguration_thenGenerateSingleObject() { EasyRandom generator = new EasyRandom(); Person person = generator.nextObject(Person.class); assertNotNull(person.getAge()); assertNotNull(person.getFirstName()); assertNotNull(person.getLastName()); }
This is how the object might look after the generation:
Person[firstName='eOMtThyhVNLWUZNRcBaQKxI', lastName='yedUsFwdkelQbxeTeQOvaScfqIOOmaa', age=-1188957731]
As we can see, generated strings might be a bit too long, and age is negative. We’ll show how this can be tweaked in further sections.
3.2. A Collection of Objects
Now, let’s say we need a collection of Person objects. Another method, objects(Class<T> t, int size) will allow us to do so.
A nice thing is, it returns stream of objects, so eventually, we could add intermediate operations to it or group as we want.
Here’s how we could generate five instances of Person:
@Test void givenDefaultConfiguration_thenGenerateObjectsList() { EasyRandom generator = new EasyRandom(); List<Person> persons = generator.objects(Person.class, 5) .collect(Collectors.toList()); assertEquals(5, persons.size()); }
3.3. Complex Objects Generation
Let’s have a look at our Employee class:
public class Employee { private long id; private String firstName; private String lastName; private Department department; private Collection<Employee> coworkers; private Map<YearQuarter, Grade> quarterGrades; }
Our class is relatively complex, it has a nested object, a collection, and a map.
Now by default, the collection generation range is from 1 to 100, so our Collection<Employee> size would result in between.
A good thing is, the objects are going to be cached and re-used, so not necessarily all are unique. Still, we might not need so many.
We’ll soon take a look at how to adjust the collection’s range, but first, let’s see at another issue we might run into.
In our domain, we have a YearQuarter class that represents a quarter of a year.
There’s a bit of logic to set up the endDate to point exactly to 3 months after the start date:
public class YearQuarter { private LocalDate startDate; private LocalDate endDate; public YearQuarter(LocalDate startDate) { this.startDate = startDate; autoAdjustEndDate(); } private void autoAdjustEndDate() { endDate = startDate.plusMonths(3L); } }
We must note, EasyRandom uses reflection to construct our objects, so generating this object through the library will result in data that, most likely, won’t be useful for us as our constraint of 3 months simply won’t be preserved.
Let’s have a look at how we could address this issue.
3.4. Generation Configuration
In the below configuration, we supply our custom configuration via EasyRandomParameters.
First, we explicitly state our desired string length and collections size. Next, we exclude some of the fields from generation, let’s say we had a reason to have just nulls.
Here, we’ve used the handy FieldPredicates utility to chain the exclusion predicates.
After that, we exclude everything from “not.existing.pkg” Java package, through another handy TypePredicates utility.
And finally, as promised, we address the issue with startDate and endDate generation of YearQuarter class by applying our custom YearQuarterRandomizer:
@Test void givenCustomConfiguration_thenGenerateSingleEmployee() { EasyRandomParameters parameters = new EasyRandomParameters(); parameters.stringLengthRange(3, 3); parameters.collectionSizeRange(5, 5); parameters.excludeField(FieldPredicates.named("lastName").and(FieldPredicates.inClass(Employee.class))); parameters.excludeType(TypePredicates.inPackage("not.existing.pkg")); parameters.randomize(YearQuarter.class, new YearQuarterRandomizer()); EasyRandom generator = new EasyRandom(parameters); Employee employee = generator.nextObject(Employee.class); assertEquals(3, employee.getFirstName().length()); assertEquals(5, employee.getCoworkers().size()); assertEquals(5, employee.getQuarterGrades().size()); assertNotNull(employee.getDepartment()); assertNull(employee.getLastName()); for (YearQuarter key : employee.getQuarterGrades().keySet()) { assertEquals(key.getStartDate(), key.getEndDate().minusMonths(3L)); } }
4. Conclusion
Manually setting up a model, DTO or entity objects might be cumbersome and result in less readable code and duplications. EasyRandom is a nice tool that can save time and help with it.
As we saw, the library doesn’t generate meaningful String objects, but there’s another tool called Java Faker with which we could create custom randomizers for the fields to sort it out as well.
Also, to have a deeper view of the library and see how much more it can be configured, we might have a look at its Github Wiki page.
As usual, the code can be found over the GitHub.