«1. Обзор

В этом руководстве мы покажем, как создавать объекты Java с помощью библиотеки EasyRandom.

2. EasyRandom

В некоторых случаях нам понадобится набор объектов модели, которые мы будем использовать для целей тестирования. Или мы хотели бы заполнить нашу тестовую базу данных некоторыми данными, которые мы собираемся использовать. Затем, возможно, мы захотим иметь коллекции фиктивных DTO для отправки обратно нашему клиенту.

Настройка одного, двух или нескольких таких объектов может быть простой, если они не сложные. Тем не менее, может быть случай, когда нам понадобятся сотни из них сразу, не пачкая рук ручной настройкой.

Здесь в дело вступает EasyRandom. EasyRandom — это библиотека, которую легко использовать, она практически ничего не требует настройки и, просто минуя тип класса, создаст для нас целые графы объектов.

Давайте посмотрим, насколько это просто.

3. Зависимость Maven

Во-первых, давайте добавим зависимость easy-random-core Maven в наш pom.xml:

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

4. Генерация объектов

Два самых важных класса в библиотеке: :

    EasyRandom, который будет генерировать объекты, и EasyRandomParameters, который позволяет настроить процесс генерации и сделать его более предсказуемым.

4.1. Одиночный объект

В нашем первом примере генерируется простой случайный объект Person, который не имеет ни вложенных объектов, ни коллекций, а только целое число и две строки.

Давайте сгенерируем один экземпляр нашего объекта, используя nextObject(Class\u003cT\u003e t):

@Test
void givenDefaultConfiguration_thenGenerateSingleObject() {
    EasyRandom generator = new EasyRandom();
    Person person = generator.nextObject(Person.class);

    assertNotNull(person.getAge());
    assertNotNull(person.getFirstName());
    assertNotNull(person.getLastName());
}

Вот как может выглядеть объект после генерации:

Person[firstName='eOMtThyhVNLWUZNRcBaQKxI', lastName='yedUsFwdkelQbxeTeQOvaScfqIOOmaa', age=-1188957731]

Как мы видим, сгенерированные строки может быть слишком длинным, а возраст отрицательным. Мы покажем, как это можно настроить в следующих разделах.

4.2. Коллекция объектов

Теперь предположим, что нам нужна коллекция объектов Person. Другой метод, objects(Class\u003cT\u003e t, int size) позволит нам сделать это.

Приятно то, что он возвращает поток объектов, поэтому в конечном итоге мы можем добавить к нему промежуточные операции или сгруппировать, как захотим.

Вот как мы можем сгенерировать пять экземпляров Person:

@Test
void givenDefaultConfiguration_thenGenerateObjectsList() {
    EasyRandom generator = new EasyRandom();
    List<Person> persons = generator.objects(Person.class, 5)
        .collect(Collectors.toList());

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

4.3. Генерация сложных объектов

Давайте посмотрим на наш класс Employee:

public class Employee {
    private long id;
    private String firstName;
    private String lastName;
    private Department department;
    private Collection<Employee> coworkers;
    private Map<YearQuarter, Grade> quarterGrades;
}

Наш класс относительно сложен, он имеет вложенный объект, коллекцию и карту.

Теперь по умолчанию диапазон генерации коллекции составляет от 1 до 100, поэтому размер нашей коллекции\u003cEmployee\u003e будет между ними.

Хорошо, что объекты будут кэшироваться и использоваться повторно, поэтому не обязательно все они будут уникальными. Тем не менее, нам может не понадобиться так много.

Вскоре мы рассмотрим, как настроить диапазон коллекции, но сначала давайте посмотрим на другую проблему, с которой мы можем столкнуться.

В нашем домене есть класс YearQuarter, представляющий четверть года.

Есть немного логики, чтобы настроить endDate так, чтобы он указывал точно на 3 месяца после даты начала:

public class YearQuarter {

    private LocalDate startDate;
    private LocalDate endDate;

    public YearQuarter(LocalDate startDate) {
        this.startDate = startDate;
        autoAdjustEndDate();
    }

    private void autoAdjustEndDate() {
        endDate = startDate.plusMonths(3L);
    }
}

Мы должны отметить, что EasyRandom использует отражение для создания наших объектов, поэтому создание этого объекта с помощью библиотеки будет приведут к получению данных, которые, скорее всего, нам не пригодятся, так как наше ограничение в 3 месяца просто не сохранится.

Давайте посмотрим, как мы могли бы решить эту проблему.

4.4. Конфигурация генерации

В приведенной ниже конфигурации мы предоставляем нашу пользовательскую конфигурацию через EasyRandomParameters.

Во-первых, мы явно указываем желаемую длину строки и размер коллекций. Далее мы исключаем часть полей из генерации, допустим, у нас была причина иметь только нули.

Здесь мы использовали удобную утилиту FieldPredicates для объединения предикатов исключения.

После этого исключаем все из Java-пакета not.existing.pkg с помощью еще одной удобной утилиты TypePredicates.

И, наконец, как и было обещано, мы решаем проблему с генерацией startDate и endDate класса YearQuarter, применяя наш собственный 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));
    }
}

5. Заключение

Ручная настройка модели, DTO или объектов сущности может быть громоздким и привести к менее читаемому коду и дублированию. EasyRandom — хороший инструмент, который может сэкономить время и помочь с ним.

«Как мы видели, библиотека не генерирует осмысленные объекты String, но есть еще один инструмент под названием Java Faker, с помощью которого мы можем создавать собственные рандомизаторы для полей, чтобы также их сортировать.

Кроме того, чтобы получить более полное представление о библиотеке и увидеть, насколько больше ее можно настроить, мы могли бы заглянуть на ее страницу Github Wiki.

Как обычно, код можно найти на GitHub.