在日常的测试中,我们经常需要提前准备一大堆测试数据,用来验证业务逻辑。当然对于简单的数据类型完全可以通过 JDK 自带的 Random 类来实现。但是对于一个比较复杂的类,或者参数的格式有特殊要求的时候,Random 就不适用了,这个时候就需要借助一些能够生成测试数据的框架。
Random
我在实际调研中,找到了 2 个在个人看来还不错的生成框架,他们分别是:
下面我将一一介绍这些框架的优缺点以及适用场景。话不多说,直接开始撸代码。
首先出场的是 JmockData 框架,它是官方定义如下:
一款实现模拟JAVA类型或对象的实例化并随机初始化对象的数据的工具框架。
<dependency> <groupId>com.github.jsonzou</groupId> <artifactId>jmockdata</artifactId> <version>4.2.0</version> </dependency>
@Test public void testBaseType(){ // 基础数据类型 System.out.println(JMockData.mock(byte.class)); System.out.println(JMockData.mock(int.class)); System.out.println(JMockData.mock(long.class)); System.out.println(JMockData.mock(double.class)); System.out.println(JMockData.mock(float.class)); System.out.println(JMockData.mock(String.class)); System.out.println(JMockData.mock(BigDecimal.class)); // 基础数据类型的数组 System.out.println(JMockData.mock(byte[].class)); System.out.println(JMockData.mock(int[].class)); System.out.println(JMockData.mock(long[].class)); System.out.println(JMockData.mock(double[].class)); System.out.println(JMockData.mock(float[].class)); System.out.println(JMockData.mock(String[].class)); System.out.println(JMockData.mock(BigDecimal[].class)); }
0 2610 3401 8582.18 7194.44 5Xu7 9051.92 [B@7fbe847c [I@41975e01 [J@c2e1f26 [D@dcf3e99 [F@6d9c638 [Ljava.lang.String;@7dc5e7b4 [Ljava.math.BigDecimal;@1ee0005
/** * java bean 测试 */ @Test public void testJavaBean(){ Person mock = JMockData.mock(Person.class); System.out.println(mock); }
Person[address=RrayfQIK,age=5863,idCard=SDn,name=j]
这里可以看到,使用 JMockdata.mock(xx.class); 可以很容易的生成一个 JavaBean。框架通过反射,在底层遍历获得类的属性与类型,然后填充数据。
JMockdata.mock(xx.class);
但是与此同时,大家也发现了,虽然我们可以的的确确的生成了一个 Person 类,也给它的每个属性都填充了值,但是生成的数据只是根据类型简单生成的,比如 age 字段被填充的是 5863。如果数据有现实含义,没有规则的随机就很容易出现乌龙。
Person
age
要解决这个问题,我们就要限制随机数据的范围,可以通过它的配置功能实现。
@Test public void testJavaBeanWithConfig() { MockConfig mockConfig = new MockConfig() .subConfig("age") // 设置 int 的范围 .intRange(1, 100) .subConfig("email") // 设置生成邮箱正则 .stringRegex("[a-z0-9]{5,15}\\@\\w{3,5}\\.[a-z]{2,3}") .globalConfig(); Person mock = JMockData.mock(Person.class, mockConfig); System.out.println(mock); }
Person[address=hXttj2s,age=2,[email protected],idCard=V5bBdX,name=KM8]
可以看到 age 跟 email 已经正常了,可以通过他强大的配置功能对于数据进行生成的限制,但是你也发现了,对于一些有简单边界的数据,这样做可以,否则就像 address 、 name 这样的数据,很难通过简单规则去生成。
email
而对于有现实意义的数据生成,可以使用 java-faker 框架。
<dependency> <groupId>com.github.javafaker</groupId> <artifactId>javafaker</artifactId> <version>1.0.2</version> </dependency>
@Test public void testRandomName() { Faker faker = new Faker(); final Name name = faker.name(); System.out.println("firstName : " + name.firstName()); System.out.println("username : " + name.username()); System.out.println("bloodGroup : " + name.bloodGroup()); System.out.println("suffix : " + name.suffix()); System.out.println("title : " + name.title()); System.out.println("lastName : " + name.lastName()); System.out.println("nameWithMiddle : " + name.nameWithMiddle()); System.out.println("fullName : " + name.fullName()); System.out.println("name : " + name.name()); System.out.println("prefix : " + name.prefix()); }
firstName : Hollis username : cristy.white bloodGroup : O- suffix : Sr. title : Product Implementation Specialist lastName : Johnston nameWithMiddle : Alesia Hagenes Kiehn fullName : Dr. Pat Marvin name : Ms. Jamal Rau prefix : Mr.
可以看到 java-faker 生成数据特别的方便,基本格式如下:
Faker faker = new Faker(); final Xx xx = faker.xx(); xx.yyyy;
步骤:
这里的实体对象,对应上面的 name,也就说我们要生成姓名相关的数据,拿到实体对象后还可以只获得其中的部分数据,比如姓名中的姓或名,还有前缀,甚至血型,可以说是非常全面。
而且 java-faker 支持的实体对象特别的多,如下:
Address Ancient Animal App Aqua Teen Hunger Force Artist Avatar Back To The Future Aviation Basketball Beer Bojack Horseman Book Bool Business ChuckNorris Cat Code Coin Color Commerce Company Crypto DateAndTime Demographic Disease Dog DragonBall Dune Educator Esports File Finance Food Friends FunnyName GameOfThrones Gender Hacker HarryPotter Hipster HitchhikersGuideToTheGalaxy Hobbit HowIMetYourMother IdNumber Internet Job Kaamelott LeagueOfLegends Lebowski LordOfTheRings Lorem Matz Music Name Nation Number Options Overwatch PhoneNumber Pokemon Princess Bride Relationship Terms RickAndMorty Robin RockBand Shakespeare SlackEmoji Space StarTrek Stock Superhero Team TwinPeaks University Weather Witcher Yoda Zelda
从身份证到姓名再到地址、动物、书籍、头像、职位等等,基本上覆盖了我们生活中的方方页面。
另外,java-faker 更贴心的是帮我们实现了国际化,可能刚才看了姓名的例子,有些朋友觉得这个框架好看但不好用,就拿生成姓名来说,生成都是 Johnston、Tom、Kiwi 之类英文名,在国内很少用到这些数据。其实java-faker 已经考虑到这个问题。而且只要改一行代码就可以了。
// 原代码 Faker faker = new Faker(); // 新代码 Faker faker = new Faker(Locale.CHINA); final Name name = faker.name(); System.out.println("firstName : " + name.firstName()); System.out.println("username : " + name.username()); System.out.println("bloodGroup : " + name.bloodGroup()); System.out.println("suffix : " + name.suffix()); System.out.println("title : " + name.title()); System.out.println("lastName : " + name.lastName()); System.out.println("nameWithMiddle : " + name.nameWithMiddle()); System.out.println("fullName : " + name.fullName()); System.out.println("name : " + name.name()); System.out.println("prefix : " + name.prefix());
firstName : 熠彤 username : 烨霖.龙 bloodGroup : A- suffix : IV title : Investor Division Engineer lastName : 范 nameWithMiddle : 胡思 fullName : 孟鸿涛 name : 黎航 prefix : Miss
只需要,把之前的 Faker faker = new Faker(); 改成 Faker faker = new Faker(Locale.CHINA); 即可。如果你想生成其它国家的内容也是可以的,java-faker 支持的国家如下:
bg ca ca-CAT da-DK de de-AT de-CH en en-AU en-au-ocker en-BORK en-CA en-GB en-IND en-MS en-NEP en-NG en-NZ en-PAK en-SG en-UG en-US en-ZA es es-MX fa fi-FI fr he hu in-ID it ja ko nb-NO nl pl pt pt-BR ru sk sv sv-SE tr uk vi zh-CN zh-TW
个人感觉它是 plus 版的 Random 类,方便简单的按类型生成数据,也可以自己给定配置与规则去生成,缺点,上文也说了,生成的数据没有太多实际意义,简单数据还好,如果像姓名、地址等有现实意义的数据,就不太合适了。
java-faker 其实是迁移自 ruby 中大名鼎鼎的 faker。很多语言都有他的对应迁移,比如 python、java。所以数据量和功能是很完善并且经过考验的,使用起来也很方便。实际工作中,可以优化使用。如果要说缺点,个人觉得他有些地方国际化的并不全面,比如车牌、身份证之类的。如果对于这些数据有比较严格的要求,推荐另一个项目 yindz/common-random: 简单易用的随机数据生成器。这个项目对于本地化数据,做了很多处理,基本够用。
原文链接:https://www.cnblogs.com/kiwifly/p/13431229.html