0%

快速生成测试数据

日常在写单元测试过程中,如何构造合适的测试数据是比较麻烦并且乏味的。本篇将介绍俩个工具用于生成测试数据,首先介绍Datafaker,此工具用于生成各种常见的测试数据。接着介绍easy-random,用于生成测试对象。最后介绍如何结合这俩个工具生成比较真实的测试对象。

Datafaker

简单的例子,在代码中引入以下jar包

1
2
3
4
5
<dependency>
<groupId>net.datafaker</groupId>
<artifactId>datafaker</artifactId>
<version>1.2.0</version>
</dependency>

简单使用

1
2
3
4
5
6
7
8
9
10
11
12
import net.datafaker.Faker;

Faker faker = new Faker();

// 生成完整名称
String name = faker.name().fullName();
// 生成姓
String firstName = faker.name().firstName(); // Emory
// 生成名字
String lastName = faker.name().lastName(); // Barton
// 生成街道地址
String streetAddress = faker.address().streetAddress();

结合locale生成符合当前时区的测试数据,同时设置对应的随机值,可以保证每次生成的数据都一致

1
2
3
Faker faker = new Faker(Locale.SIMPLIFIED_CHINESE,new Random(0));
String name = faker.name().fullName();
System.out.println(name); // 沈明哲

生成集合测试数据

1
2
3
List<String> names = new FakeCollection.Builder<String>() .suppliers(() -> faker.name().firstName(), () -> faker.name().lastName())
.minLen(3)
.maxLen(5).build().get();

还有更多的用法,比如自定义数据,测试文件构建等等,可以参考官方文档。

easy-random

这个主要用来随机生成对象

简单例子

1
2
3
4
5
6
7
8
9
10
EasyRandom easyRandom = new EasyRandom();
Person person = easyRandom.nextObject(Person.class);

@Data
public class Person {

private int age;

private String name;
}

使用上面方式生成的数据比较随意,不一定符合测试数据的要求,可以通过自定义填充方式,来生成合适的数据。使用方式如下,实现Randomizer来自定义生成测试数据的方式。

1
2
3
4
5
6
7
8
9
public class NameRandomizer implements Randomizer<String> {

private List<String> names = Arrays.asList("John", "Brad", "Tommy");

@Override
public String getRandomValue() {
return names.get(new Random().nextInt(2));
}
}

可以通过注解或者自定义编码来使用上面自定义的数据生成方式。下面介绍编码的方式

1
2
3
4
5
6
7
EasyRandomParameters parameters = new EasyRandomParameters()
.randomize(FieldPredicates.named("name").and(FieldPredicates.ofType(Integer.class)).and(FieldPredicates.inClass(Person.class)), new NameRandomizer())
.build();

EasyRandom easyRandom = new EasyRandom(easyRandomParameters);
Person person = easyRandom.nextObject(Person.class);
System.out.println(person);

通过上面生成的测试数据相对比较符合要求。这个工具包已经内置了很多Randomizer ,具体可以在org.jeasy.random.randomizers包下查找合适的。除了上面的方式,还可以结合bean validation来生成合适的测试数据,例子如下
首先需要引入如下的包

1
2
3
4
5
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-random-bean-validation</artifactId>
<version>${latest.version}</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Person {

private String name;

@javax.validation.constraints.Size(min = 5, max = 10)
private List<String> nickNames;

@javax.validation.constraints.Past
private Date birthDate;

// constructors, getters and setters omitted
}


// 测试代码
LocalDate today = LocalDate.now();
EasyRandomParameters parameters = new EasyRandomParameters().collectionSizeRange(1, 4)
.randomize(FieldPredicates.named("birthDate").and(FieldPredicates.inClass(Person.class)),
new LocalDateRangeRandomizer(today, today.plusYears(10)));
EasyRandom easyRandom = new EasyRandom(parameters);

// when
Person person = easyRandom.nextObject(Person.class);

// then
assertThat(person.names.size()).isBetween(5, 10); // Bean Validation constraint parameters take precedence
assertThat(person.birthDate).isAfterOrEqualTo(today); // custom randomizers take precedence

上面的例子同时也验证对象上的注解优先于全局注册的Randomizer

结合使用

前面的例子可以看出,datafaker能够生成比较真实的测试数据,easy-random能够快速填充对象。可以通过以下方式结合使用

1
2
3
4
5
6
7
Faker faker = new Faker(Locale.SIMPLIFIED_CHINESE);
EasyRandomParameters easyRandomParameters = new EasyRandomParameters()
.randomize(FieldPredicates.named("name"),()->faker.name().name())
.randomize(FieldPredicates.named("age"),()->new Random().nextInt(100));
EasyRandom easyRandom = new EasyRandom(easyRandomParameters);
Person person = easyRandom.nextObject(Person.class);
System.out.println(person);