Java EasyRandom快速指南

2023/05/09

1. 概述

在本教程中,我们将介绍如何使用EasyRandom库生成Java对象。

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对象,该对象没有嵌套对象属性、集合属性,只有一个Integer和两个Strings属性。

让我们使用nextObject(Class<T> t)生成Person对象的一个实例

@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<T> t, int size)允许我们实现这一点。

有一个好处是,它返回对象流,因此最终,我们可以根据需要向其添加中间操作或分组

以下是一个生成五个Person实例的例子:

@Test
void givenDefaultConfiguration_thenGenerateObjectsList() {
    EasyRandom generator = new EasyRandom();
    List<Person> persons = generator.objects(Person.class, 5)
        .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;
}

这个类相对复杂,它有一个嵌套对象、一个集合和一个Map。

现在,默认情况下,集合生成范围为1到100,因此我们的Collection<Employee>大小将介于两者之间。

一个好处是,对象将被缓存和重用,因此不一定都是唯一的。不过,我们可能不需要这么多。

我们很快就会了解如何调整集合的范围,但首先,让我们看看我们可能会遇到的另一个问题。

在我们的域类中,我们有一个YearQuarter,它代表一年的四分之一。

将endDate设置为正好指向startDate后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工具类来链接排除谓词。

之后,我们通过另一个方便的TypePredicates工具类从“not.existing.pkg” Java包中排除所有内容。

最后,正如承诺的那样,我们通过应用我们的自定义YearQuarterRandomizer来解决YearQuarter类的startDate和endDate生成问题

@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上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章