测试数据生成工具库的创建思路


说明:

本项目github地址 https://github.com/hskill/magic

  1. 本项目参考了以下项目
  2. 该项目使用了 lombok ,如果需要调试或修改代码,请在 idea 中开启相关插件与功能。

使用场景

(1)向数据库生成测试数据 (2)快速搭建后端服务,向前端发送测试数据,快速开发原型系统 (3)增加单元测试的真实性,为测试代码生成测试数据

快速认识

(1)设置数据属性

使用 Schema.serial 使用时传入数据名称,以及需要的数据属性。

// code(1)

Schema.serial("user"
    new Id("id"),
    new Name("name"),
    new Age("age")
);

第一个参数:名称

唯一的名称标识。

其它参数:随机数据域

new Id("id") ,该对象将生成一个唯一的数字标识;除此之外,本示例代码中还使用了 Name 与 Age。

注意,随机数据域的构造方法一般都需要传入一个字符串值,作为数据域的名称,该名称对应生成数据的名称。

(2)如何生成数据

可以在 Schema 对象上,可以方便地调用数据生成方法(详见结果生成部分)。

// code(2)

Schema user = Schema.serial("user",
    new Id("id"),
    new Name("name"),
    new Age("age")
);

// 简单使用:按模板生成内容字符串,并打印到终端命令行。
user.size(10)
    .asText()
    .template("${id} - ${name} - ${age}")
    .toPrint();

该示例中,size 是指定生成的数量,该值若不设置,默认将生成 100个数据;asText 是指生成为文本;template 是传入文本生成的模板(按freemarker模板语法);toPrint 是指结果打印在控制台屏幕上。

(3)数据结果

按照 code (2) 的代码执行,将打印为以下文本内容。

772375471734792192 - 金伴花 - 48
772375471734792193 - 朱七七 - 49
772375471734792194 - 潘乘风 - 21
772375471734792195 - 金不畏 - 39
772375471734792196 - 铁成钢 - 31
772375471734792197 - 小雯 - 43
772375471734792198 - 火凤凰 - 44
772375471738986496 - 凤娟 - 41
772375471738986497 - 孟星魂 - 47
772375471738986498 - 烈火夫人 - 38

Schema

Schema 是内容生成的主要入口类,它接受名称随机数据域定义对象.

Schema.serial

SerialSchema Schema.serial(String mark, Randomable... ables)

静态方法,该方法如 code(1) 与 code(2) 显示,将返回一个 SerialSchema 类对象( Schema 的子类 ),该对象将产生一个列表数据(List<Map<String, Object>)。

参数:mark

名称用于标识。

参数:ables

可传入多个随机数据域,用于数据定义。

Schema.only

OnlySchema Schema.only(String name, Randomable... ables)

静态方法,该方法与 Schema.serial 类似,主要返回 OnlySchema 对象( Schema 的子类),该对象将产生一个数据(Map<String, Object>)。

Schema.get

Schema Schema.get(String mark) 静态方法,以指定的名称标识,获取已定义过的 Schema 对象。

参数:mark

名称标识

getMark

String getMark() 实例方法,获取该对象名称标识。

asText

Text asText() 实例方法,获取 Text 结果处理类实例。

asObj

Obj asObj() 实例方法,获取 Obj 结果处理类实例。

asJson

Json asJson() 实例方法,获取 Json 结果处理实例。

asJdbc

Jdbc asJdbc 实例方法,获取 Jdbc 结果处理实例。

随机数据域使用

(1)简单介绍

随机数据的生成,主要依靠随机数据域产生数据,在 Schema.serial 方法中,需要传入一系列的数据域对象。例如,在 code(1) 中,使用了 IdNameAge 进行实例化。

这些实例对象,将分别生成对应的数据,如 Id 将生成一系列唯一的长整数标识,Name 将生成随机的中文名字,Age 将生成随机的年龄数。

随机数据域在项目代码中就是实现了 Randomable 接口的类,通过该类 next 实例方法,不断产生随机生成数据。

按照实际需要,本项目定义了一系列的随机数据域,更多介绍,请查看本文档后叙内容: 随机数据域

(2)单个数据生成与关联

假设创建人员数据,除了人员基础信息外,还定义了一个地址数据,而地址数据由 provincecity 组成。在一些Java类中,该实现的可能方式是在类User中定义了Address类,也即通常说的 1-1 关系,代码如下:

// code(3)

Schema.serial("user", 
    new Id("id"),
    new Name("name"),
    
    Schema.only("address",
        new Pronvince("province"),
        new City("city")
    )
)

以上代码运行结果,将产生关联数据。 该代码其实表示一个内在含义,就是 Schema 对象也实现了 Randomable

(3)列表数据生成与关联

按 code(1) 或 code(2) ,对每个属性可以生成单一值,但往往属性也需要生成列表数据。 例如,简单的老师-学生关系,一个老师数据中,包含多个学生数据,在面向对象中,通常通过列表属性实现,在数据库中由外键实现,也即通常说的 1-N 的关系。

// code(4)

Schema.serial("teacher",
    new Id("id"),
    new Name("name")
);

在学生数据表中,需要维护一个老师的id(teacherId),简单的方法是只有把刚才生成过的老师数据中的id收集起来,插入到学生数据中即可。

// code (5)

Schema.serial("student", 
    new Id("id"),
    new Name("name"),

    // 重点在这里,使用刚才给老师表标明的名称 teacher
    // 使用getProduced方法,返回一个随机数据域
    // 
    // 需要传入两个参数,
       // (1) id 表示在teahcer中的数据域
    // (2) teacherId 表示在当前表中新建的随机数据域的id
    Schema.get("teacher").getProduced("id", "teacherId")
);

以上代码运行结果,学生将得到一个 teahcerId 数据,该数据的取值来源是生成的老师数据中 id 的值。

结果生成

通过 Schema 生成数据,其实是生成 Map<String, Object> 对象,该对象通过随机数据域的名称作为键,而生成的数据为值。

其中,在 SerialSchema 中生成列表数据,即 List<Map<String, Object> 数据,而 OnlySchema 就是生成单个 Map 数据。

Map 对象可以通过不同的结果处理器,转换为不同格式的数据,或进行不同的数据处理。

(1)生成文本

Schema 中使用 asText 返回 Text 对象,可以用于生成文本结果。可以考虑在生成 sqlhtml 等文本结果的场景使用。

template

Text template(String template)

实例方法,数据生成为文本的模板字符串。模板字符串使用 freemarker 模板语法(项目使用freemarker库)将数据生成为字符串。

seperator

Text seperator(String seperator)

实例方法,用于在每一条数据中插入间隔字符串,默认为换行符。

toList

List<String> toList()

实例方法,返回列表字符串。

toFile

void toFile(String filename)

实例方法,将字符串写入文本文件,需传入带完整路径的文件名。

toWriter

void toWriter(Writer writer)

实例方法,将字符串写入writer。

toPrint

void toPrint()

实例方法,将字符串打印到终端命令行。

代码示例:

// code (6)

Schema user = Schema.serial("user", 
    new Id("id"), 
    new Name("name"), 
    new Age("age")
);

// 方法1 返回字符串列表
List<String> strList = user.asText()
.template("INSERT INTO `user` VALUES('${id}', '${name}', '${age}'")
.toList();

// 方法2 直接写文件
user.asText()
.template("INSERT INTO `user` VALUES('${id}', '${name}', '${age}'")
.toFile("/User/Jevon/Source/project/insert_user.sql");

// 方法3 通过writer作用 例如 System.out
user.asText()
.template("INSERT INTO `user` VALUES('${id}', '${name}', '${age}'")
.toWriter(new OutputSteamWriter(System.out));

// 方法4 直接打印内容到终端命令行
user.asText()
.template("INSERT INTO `user` VALUES('${id}', '${name}', '${age}'")
.toPrint();

(2)生成Json

Schema 中使用 asJson 返回 Json 对象,可以将通过 alibaba fastjson 将生成的数据直接转为json字符串 。

适合在web应用中,向前端返回json数据。

注意,以下相同方法不再详细说明。

target

Json target(Class<?> clazz) 实例方法,数据生成json时,使用类进行数据转换。

toStr

String toStr() 实例方法,数据生成json字符串。

toWriter

void toWriter() 实例方法。

toPrint

void toPrint() 实例方法。

toFile

void toFile(String filename) 实例方法。

代码示例:

// code(7)
Schema user = Schema.serial("user",
    new Id("id"),
    new Name("name"),
    new Age("age")
);

// 生成字符串
String json = user.asJson().toStr();

// 使用 class 进行序列化
String json = user.asJson().target(User.class).toStr();

(3)生成Java对象数据

Schema 中使用 asObj 返回 Obj 对象,可以将数据转换为Java对象。

适合在Java单元测试中使用。

toList

List<T> toList(Class<T> target) 实例方法,返回指定类的对象列表。

to

T to(Class<T> target) 实例方法,返回指定类(单个)对象。

代码示例:

// code (8) 

// 省略编写 getter 与 setter
public class Person {
    private Long id;
    private String name;
    private int age;
}

Schema.serial("user", 
    new Id("id"), 
    new Name("name"), 
    new Age("age")
).asObj().toList(Person.class);

(4)向JDBC数据库写数据

Schema 中使用 asJdbc 生成 Jdbc 对象,该对象用于直接向数据库生成数据(暂只支持Mysql)。

template

Jdbc template(String template) 实例方法,可以指定向数据写数据的插入SQL模板。

url

Jdbc url(String url) 实例方法,指定数据库url。优先使用该变量。

host

Jdbc host(String host) 实例方法,指定数据库主机。

user

Jdbc user(String user) 实例方法,指定数据库用户名。

password

Jdbc password(String password) 实例方法,指定数据库密码。

db

Jdbc db(String db) 实例方法,指定数据库。

table

Jdbc table(String table)

实例方法,指定插入数据的表名。注意,该方法不与template方法同时使用,如果已经指定了template,不使用该参数,如果未指定template,将自动按表名与数据名称,生成sql语句进行执行。

to

Jdbc to() 实例方法,执行数据库插入数据操作。

代码示例:

// code (9)

Schema user = Schema.serial("user", 
    new Id("id"),
    new Name("name"),
    new Age("age")
)

// 按模板生成sql执行
user.asJdbc()
.host("localhost")
.user("root")
.password("123456")
.db("example")
.template("INSERT INTO `user` VALUES(${id}, '${name}', ${age}")
.to();

// 按表名自动生成sql执行
user.asJdbc()
.host("localhost")
.user("root")
.password("123456")
.db("example")
.table("user")
.to();

使用实践

在项目中,可以新建一个 Generator 类,在该类中定义一系列类型为 Schema 静态常量。

public class Generator {
    public static final Schema user = Schema.serial("user", 
        new Id("id"),
        new Name("name"),
        new Email("email"),
        new Cellphone("cellphone")
    );

    public static final Schema article = Schema.serial("article",
        new Id("id"),
        new Paragraph("title"),
        new Article("content"),
        new DateTime("created")
    );
}

能过以上代码,就可以在不同场合同时使用,例如在后端数据库数据生成,web层json数据生成等。


@RestController
public class UserController {
    
    @GetMapping("/user")
    public String find() {
        return Generator.user.asJson().toStr();
    }
}
public void UserTest {
    
    @Test
    public void test() {
        Generator.user.asJdbc()
            .url("jdbc:myql")
            .table("user").to();
    }
}

贵州中测信息技术有限公司

创造智慧体验