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


    image.png

    前言


    在日常的测试中,我们经常需要提前准备一大堆测试数据,用来验证业务逻辑。当然对于简单的数据类型完全可以通过 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));
        }
    

    运行结果
    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
    

    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 : 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;
    


    步骤:

    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 : 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


    总结

    JmockData

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

    Java-faker

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

  • 相关阅读:
    info命令简介
    scheme代码返回3个数中较大2个数之和
    mitscheme的标准库函数
    如何理解认知
    mitscheme编辑和装入程序文件
    scheme格式化输出字符串
    SQLServer中批量导出所有作业或链接脚本
    DAMA学习笔记(1)
    SQLServer AlwaysON修改可用性组的监听端口
    SQLServer将数据库置为只读
  • 原文地址:https://www.cnblogs.com/kiwifly/p/13431229.html
Copyright © 2020-2023  润新知