【测试】Java如何优雅的生成测试数据

编程

<a name="EZS3a"></a>

前言

<br />在日常的测试中,我们经常需要提前准备一大堆测试数据,用来验证业务逻辑。当然对于简单的数据类型完全可以通过 JDK 自带的 Random 类来实现。但是对于一个比较复杂的类,或者参数的格式有特殊要求的时候,Random 就不适用了,这个时候就需要借助一些能够生成测试数据的框架。<br />

<a name="ndSj3"></a>

相关框架

<br />我在实际调研中,找到了 2 个在个人看来还不错的生成框架,他们分别是:<br />

  1. jmockdata
  2. java-faker

<br />下面我将一一介绍这些框架的优缺点以及适用场景。话不多说,直接开始撸代码。<br />

<a name="1Zjdk"></a>

JmockData

<br />首先出场的是 JmockData 框架,它是官方定义如下:<br />

一款实现模拟JAVA类型或对象的实例化并随机初始化对象的数据的工具框架。

<a name="2fgiK"></a>

依赖

  <dependency>

<groupId>com.github.jsonzou</groupId>

<artifactId>jmockdata</artifactId>

<version>4.2.0</version>

</dependency>

<a name="aDRSa"></a>

基础类型数据生成

    @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));

}

<a name="90C5R"></a>

运行结果

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

<a name="Ot1OR"></a>

JavaBean 类型数据生成

    /**

* java bean 测试

*/

@Test

public void testJavaBean(){

Person mock = JMockData.mock(Person.class);

System.out.println(mock);

}

<a name="6D9Vm"></a>

运行结果

Person[address=RrayfQIK,age=5863,idCard=SDn,name=j]

<br />这里可以看到,使用 JMockdata.mock(xx.class); 可以很容易的生成一个 JavaBean。框架通过反射,在底层遍历获得类的属性与类型,然后填充数据。<br />

<br />但是与此同时,大家也发现了,虽然我们可以的的确确的生成了一个 Person 类,也给它的每个属性都填充了值,但是生成的数据只是根据类型简单生成的,比如 age 字段被填充的是 5863。如果数据有现实含义,没有规则的随机就很容易出现乌龙。<br />

<br />要解决这个问题,我们就要限制随机数据的范围,可以通过它的配置功能实现。<br />

<a name="WDvel"></a>

使用随机配置

    @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);

}

<a name="QHgDU"></a>

运行结果

Person[address=hXttj2s,age=2,email=w14hnn@UvFB9.kt,idCard=V5bBdX,name=KM8]

<br />可以看到 ageemail 已经正常了,可以通过他强大的配置功能对于数据进行生成的限制,但是你也发现了,对于一些有简单边界的数据,这样做可以,否则就像 address 、 name 这样的数据,很难通过简单规则去生成。<br />

<br />而对于有现实意义的数据生成,可以使用 java-faker 框架。<br />

<a name="8WGhr"></a>

Java-faker

<a name="zHWKG"></a>

依赖

<dependency>

<groupId>com.github.javafaker</groupId>

<artifactId>javafaker</artifactId>

<version>1.0.2</version>

</dependency>

<a name="THku1"></a>

数据生成

    @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());

}

<a name="BHe20"></a>

生成结果

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.

<br />可以看到 java-faker 生成数据特别的方便,基本格式如下:<br />

        Faker faker = new Faker();

final Xx xx = faker.xx();

xx.yyyy;

<br />步骤:

  1. 创建 faker 对象
  2. 通过 faker 对象获得要生成的实体对象
  3. 调用实体对象获得对于生成的部分

<br />这里的实体对象,对应上面的 name,也就说我们要生成姓名相关的数据,拿到实体对象后还可以只获得其中的部分数据,比如姓名中的姓或名,还有前缀,甚至血型,可以说是非常全面。<br />

<br />而且 java-faker 支持的实体对象特别的多,如下:<br />

  • 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

<br />从身份证到姓名再到地址、动物、书籍、头像、职位等等,基本上覆盖了我们生活中的方方页面。<br />

<br />另外,java-faker 更贴心的是帮我们实现了国际化,可能刚才看了姓名的例子,有些朋友觉得这个框架好看但不好用,就拿生成姓名来说,生成都是 Johnston、Tom、Kiwi 之类英文名,在国内很少用到这些数据。其实java-faker 已经考虑到这个问题。而且只要改一行代码就可以了。<br />

<a name="FfJwy"></a>

修改后的代码

		// 原代码 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());

<a name="JkEhj"></a>

生成结果

firstName : 熠彤

username : 烨霖.龙

bloodGroup : A-

suffix : IV

title : Investor Division Engineer

lastName : 范

nameWithMiddle : 胡思

fullName : 孟鸿涛

name : 黎航

prefix : Miss

<br />只需要,把之前的 Faker faker = new Faker(); 改成 Faker faker = new Faker(Locale.CHINA); 即可。如果你想生成其它国家的内容也是可以的,java-faker 支持的国家如下:<br />

  • 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

<br />

<br />

<a name="clUxh"></a>

总结

<a name="OYU3d"></a>

JmockData

个人感觉它是 plus 版的 Random 类,方便简单的按类型生成数据,也可以自己给定配置与规则去生成,缺点,上文也说了,生成的数据没有太多实际意义,简单数据还好,如果像姓名、地址等有现实意义的数据,就不太合适了。

<a name="g6D1y"></a>

Java-faker

java-faker 其实是迁移自 ruby 中大名鼎鼎的 faker。很多语言都有他的对应迁移,比如 python、java。所以数据量和功能是很完善并且经过考验的,使用起来也很方便。实际工作中,可以优化使用。如果要说缺点,个人觉得他有些地方国际化的并不全面,比如车牌、身份证之类的。如果对于这些数据有比较严格的要求,推荐另一个项目 yindz/common-random: 简单易用的随机数据生成器。这个项目对于本地化数据,做了很多处理,基本够用。<br />

以上是 【测试】Java如何优雅的生成测试数据 的全部内容, 来源链接: utcz.com/z/519054.html

回到顶部