前言


在日常的测试中,咱们常常须要提前准备一大堆测试数据,用来验证业务逻辑。当然对于简略的数据类型齐全能够通过 JDK 自带的 Random 类来实现。然而对于一个比较复杂的类,或者参数的格局有特殊要求的时候,Random 就不实用了,这个时候就须要借助一些可能生成测试数据的框架。

相干框架


我在理论调研中,找到了 2 个在集体看来还不错的生成框架,他们别离是:

  1. jmockdata
  2. java-faker


上面我将一一介绍这些框架的优缺点以及实用场景。话不多说,间接开始撸代码。

JmockData


首先出场的是 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));    }

运行后果
0261034018582.187194.445Xu79051.92[B@7fbe847c[I@41975e01[J@c2e1f26[D@dcf3e99[F@6d9c638[Ljava.lang.String;@7dc5e7b4[Ljava.math.BigDecimal;@1ee0005

JavaBean 类型数据生成

    /**     * 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。框架通过反射,在底层遍历取得类的属性与类型,而后填充数据。


然而与此同时,大家也发现了,尽管咱们能够的的确确的生成了一个 Person 类,也给它的每个属性都填充了值,然而生成的数据只是依据类型简略生成的,比方 age 字段被填充的是 5863。如果数据有事实含意,没有规定的随机就很容易呈现乌龙。


要解决这个问题,咱们就要限度随机数据的范畴,能够通过它的配置性能实现。

应用随机配置

    @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=w14hnn@UvFB9.kt,idCard=V5bBdX,name=KM8]


能够看到 ageemail 曾经失常了,能够通过他弱小的配置性能对于数据进行生成的限度,然而你也发现了,对于一些有简略边界的数据,这样做能够,否则就像 address 、 name 这样的数据,很难通过简略规定去生成。


而对于有现实意义的数据生成,能够应用 java-faker 框架。

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 : Hollisusername : cristy.whitebloodGroup : O-suffix : Sr.title : Product Implementation SpecialistlastName : JohnstonnameWithMiddle : Alesia Hagenes KiehnfullName : Dr. Pat Marvinname : Ms. Jamal Rauprefix : Mr.


能够看到 java-faker 生成数据特地的不便,根本格局如下:

        Faker faker = new Faker();        final Xx xx = faker.xx();        xx.yyyy;


步骤:

  1. 创立 faker 对象
  2. 通过 faker 对象取得要生成的实体对象
  3. 调用实体对象取得对于生成的局部


这里的实体对象,对应下面的 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 : IVtitle : Investor Division EngineerlastName : 范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




总结

JmockData

个人感觉它是 plus 版的 Random 类,不便简略的按类型生成数据,也能够本人给定配置与规定去生成,毛病,上文也说了,生成的数据没有太多实际意义,简略数据还好,如果像姓名、地址等有现实意义的数据,就不太适合了。

Java-faker

java-faker 其实是迁徙自 ruby 中赫赫有名的 faker。很多语言都有他的对应迁徙,比方 python、java。所以数据量和性能是很欠缺并且通过考验的,应用起来也很不便。理论工作中,能够优化应用。如果要说毛病,集体感觉他有些中央国际化的并不全面,比方车牌、身份证之类的。如果对于这些数据有比拟严格的要求,举荐另一个我的项目 yindz/common-random: 简略易用的随机数据生成器。这个我的项目对于本地化数据,做了很多解决,根本够用。