拓展阅读
RandomBeans
项目状态
截至2020年11月15日,Easy Random 处于维护模式。这意味着从现在开始只会处理 bug 修复(除了在 Java 16 发布时将发布的 records 支持)。目前支持的版本为基于 Java 11 的版本 5.0.x 和基于 Java 8 的版本 4.3.x。请尽早考虑升级到其中一个版本。
最新消息
2020年11月15日:Easy Random v5.0.0 发布,现在基于 Java 11。在功能上,此版本与 v4.3.0 相同。请查看发布说明以获取更多详细信息。 2020年11月7日:Easy Random v4.3.0 现已发布,支持泛型和流畅的 setter!您可以在更改日志中找到所有详细信息。
什么是 Easy Random?
Easy Random 是一个生成随机 Java 对象的库。你可以将它视为 JVM 的 ObjectMother。假设你有一个类 Person,你想生成它的一个随机实例,如下所示:
EasyRandom easyRandom = new EasyRandom();
Person person = easyRandom.nextObject(Person.class);
EasyRandom#nextObject 方法能够生成任何给定类型的随机实例。
这个 EasyRandom API 是什么?
java.util.Random API 提供了 7 个方法来生成随机数据:nextInt()、nextLong()、nextDouble()、nextFloat()、nextBytes()、nextBoolean() 和 nextGaussian()。如果你需要生成一个随机的字符串?或者说你的领域对象的一个随机实例呢?Easy Random 提供了 EasyRandom API,它通过一个名为 nextObject(Class type) 的方法扩展了 java.util.Random。这个方法能够生成任何任意 Java Bean 类型的随机实例。
EasyRandomParameters 类是配置 EasyRandom 实例的主要入口点。它允许你设置所有参数以控制如何生成随机数据:
EasyRandomParameters parameters = new EasyRandomParameters()
.seed(123L)
.objectPoolSize(100)
.randomizationDepth(3)
.charset(forName("UTF-8"))
.timeRange(nine, five)
.dateRange(today, tomorrow)
.stringLengthRange(5, 50)
.collectionSizeRange(1, 10)
.scanClasspathForConcreteTypes(true)
.overrideDefaultInitialization(false)
.ignoreRandomizationErrors(true);
EasyRandom easyRandom = new EasyRandom(parameters);
有关这些参数的更多详细信息,请参阅配置参数部分。
在大多数情况下,使用默认选项就足够了,你可以使用 EasyRandom 的默认构造函数。
Easy Random 允许你通过 org.jeasy.random.api.Randomizer 接口来控制如何生成随机数据,并通过 java.util.function.Predicate 轻松地从对象图中排除一些字段:
EasyRandomParameters parameters = new EasyRandomParameters()
.randomize(String.class, () -> "foo")
.excludeField(named("age").and(ofType(Integer.class)).and(inClass(Person.class)));
EasyRandom easyRandom = new EasyRandom(parameters);
Person person = easyRandom.nextObject(Person.class);
在上面的例子中,Easy Random 将:
- 将所有 String 类型的字段设置为 “foo”(使用作为 lambda 表达式定义的 Randomizer)。
- 在类 Person 中排除名为 age、类型为 Integer 的字段。
名为 named、ofType 和 inClass 的静态方法定义在 org.jeasy.random.FieldPredicates 中,它提供了你可以与其组合使用以定义要排除的字段的常见断言。类似的名为 TypePredicates 的类可用于定义要从对象图中排除的类型。当然,你也可以使用自己的 java.util.function.Predicate 与这些预定义的断言组合使用。
为什么选择 Easy Random?
用随机数据填充 Java 对象乍一看似乎很容易,除非你的领域模型涉及许多相关的类。
在上面的例子中,假设 Person 类型定义如下:
public class Person {
private String firstName;
private String lastName;
private String email;
private Gender gender;
private Address address;
// getters and setters
}
public class Address {
private Street street;
private String zipCode;
private String city;
private String country;
// getters and setters
}
public class Street {
private int number;
private byte type;
private String name;
// getters and setters
}
public enum Gender {
MALE, FEMALE
}
如果没有 Easy Random,为了创建 Person 类的实例,你将编写以下代码:
Street street = new Street(12, (byte) 1, "Oxford street");
Address address = new Address(street, "123456", "London", "United Kingdom");
Person person = new Person("Foo", "Bar", "foo.bar@gmail.com", Gender.MALE, address);
如果这些类没有提供带有参数的构造函数(可能是一些你无法更改的遗留类型),你将编写:
Street street = new Street();
street.setNumber(12);
street.setType((byte) 1);
street.setName("Oxford street");
Address address = new Address();
address.setStreet(street);
address.setZipCode("123456");
address.setCity("London");
address.setCountry("United Kingdom");
Person person = new Person();
person.setFirstName("Foo");
person.setLastName("Bar");
person.setEmail("foo.bar@gmail.com");
person.setGender(Gender.MALE);
person.setAddress(address);
使用 Easy Random,生成一个随机的 Person 对象只需使用 new EasyRandom().nextObject(Person.class)
。
该库将递归地填充整个对象图。这是一个很大的区别!
这如何有用呢?
有时,测试装置对测试逻辑并不重要。
例如,如果我们想测试一个新的排序算法的结果,我们可以生成随机的输入数据,并断言输出是排序的,而不考虑数据本身:
@org.junit.Test
public void testSortAlgorithm() {
// Given
int[] ints = easyRandom.nextObject(int[].class);
// When
int[] sortedInts = myAwesomeSortAlgo.sort(ints);
// Then
assertThat(sortedInts).isSorted(); // 假的断言
}
另一个例子是测试领域对象的持久性,我们可以生成一个随机的领域对象,将其持久化,然后断言数据库包含相同的值:
@org.junit.Test
public void testPersistPerson() throws Exception {
// Given
Person person = easyRandom.nextObject(Person.class);
// When
personDao.persist(person);
// Then
assertThat("person_table").column("name").value().isEqualTo(person.getName()); // 断言数据库
}
还有许多其他情况下 Easy Random 可以派上用场,你可以在 wiki 中找到一个非详尽的列表。
扩展
- JUnit 扩展:在 JUnit 测试中使用 Easy Random 生成随机数据(由 glytching 提供)
- Vavr 扩展:该扩展添加了对随机化 Vavr 类型的支持(由 xShadov 提供)
- Protocol Buffers 扩展:该扩展添加了对随机化 Protocol Buffers 生成的类型的支持(由 murdos 提供)
chat
详细介绍一下 randombeans
RandomBeans
是一个 Java 库,用于生成具有随机值的 Java 对象。
该库允许你轻松地创建具有随机数据的对象,适用于测试、原型设计和其他需要使用随机数据的场景。
以下是 RandomBeans
的一些主要功能和用法:
-
简单的随机对象生成: 通过调用
RandomBeans
的静态方法,你可以轻松生成具有随机值的对象。例如:Person person = RandomBeans.of(Person.class).get();
-
配置生成选项:
RandomBeans
允许你配置生成随机对象的选项,例如是否包括 null 值、是否忽略特定字段等。可以通过使用RandomBeansBuilder
进行配置:Person person = RandomBeans.builder(Person.class) .nulls(false) .exclude("socialSecurityNumber") .get();
-
支持嵌套对象:
RandomBeans
可以递归生成嵌套对象,确保整个对象图都包含随机数据:Company company = RandomBeans.of(Company.class).get();
-
支持集合和数组: 你可以生成具有随机元素的集合或数组:
List<Person> people = RandomBeans.listOf(Person.class, 10);
-
自定义生成器: 通过实现
Randomizer
接口,你可以提供自定义的生成器,以控制特定类型的随机值生成逻辑:RandomBeans.registerRandomizer(MyType.class, new MyTypeRandomizer());
-
支持各种数据类型:
RandomBeans
支持生成各种基本数据类型、日期、枚举等类型的随机值。
下面是一个简单的示例,演示如何使用 RandomBeans
生成具有随机值的 Person
对象:
import io.github.benas.randombeans.api.EnhancedRandom;
import io.github.benas.randombeans.api.EnhancedRandomBuilder;
public class RandomBeansExample {
public static void main(String[] args) {
// 创建 EnhancedRandom 实例
EnhancedRandom enhancedRandom = EnhancedRandomBuilder.aNewEnhancedRandomBuilder().build();
// 生成随机的 Person 对象
Person person = enhancedRandom.nextObject(Person.class);
// 打印生成的 Person 对象
System.out.println(person);
}
}
在这个例子中,Person
类是一个简单的 Java Bean,EnhancedRandom
接口提供了用于生成随机对象的方法。
你可以通过构建器配置生成选项。这使得在测试中创建具有随机数据的对象变得非常容易。
参考资料
https://github.com/j-easy/easy-random