Appearance
自动化测试
全自动生成 API 自动化测试用例
介绍
诞生于我司领导的一个想法:实现全自动化测试公司产品。要求实现一下几个功能点:
自动生成 API 测试用例并填充相应的参数自动化测试要满足一些常规手动测试条件,降低手写工作量可根据JSDoc
中书写的信息生成特定的测试用例- 全平台(web、Android、iOS、小程序)测试结果比对
- 不同版本间结果比对
- 当前运行结果与上次运行结果比对
使用依赖
- typescript 解析(ts-morph)
- rollup 编译
- typescript 编译(ts-node)
- jest
- @babel/generator、@babel/template、@babel/types
总体实现思路
第一步:解析 d.ts
文件
从原有的
d.ts
中读取到类型定义,包括interface
、namespace
、type
等信息使用
ts-morph
模块来做处理,使用 api 更加可控,可读性更高tsimport { Project } from 'ts-morph'; const project = new Project(); const sourceFile = project.createSourceFile(filePath, sourceFileText, { overwrite: true, }); // 要使用 overwrite,因为如果 filePath 同名会报错。后面并不会对该文件进行修改
去递归处理生成的 sourceFile 文件,分别处理
Array
、Object
和基础类型等信息生成类型TypeData[]
:tsexport type BaseTypeDataString = 'string' | 'number' | 'boolean' | 'any' | 'void'; export type ExtTypeDataString = | 'interface' | 'Function' | 'Union' | 'Array' | 'ArrayBuffer' | 'null'; const baseTypeDatas: BaseTypeDataString[] = ['string', 'number', 'boolean', 'any', 'void']; interface BaseTypeData { type: BaseTypeDataString | ExtTypeDataString; doc?: DocsData; value?: string | number | boolean; // | null } export interface InterfaceTypeData extends BaseTypeData { type: 'interface'; name: string; properties: Record<string, PropertyTypeData>; } export interface FunctionTypeData extends BaseTypeData { type: 'Function'; params: ParamTypeData[]; return: TypeData; key?: string; } export interface UnionTypeData extends BaseTypeData { type: 'Union'; types: TypeData[]; } export interface ArrayTypeData extends BaseTypeData { type: 'Array'; elementType: TypeData; } export interface ArrayBufferTypeData extends BaseTypeData { type: 'ArrayBuffer'; } interface OptionalTypeData extends BaseTypeData { key: string; optional: boolean; } export type TypeData = | BaseTypeData | InterfaceTypeData | FunctionTypeData | UnionTypeData | ArrayTypeData | ArrayBufferTypeData;
处理 docs 信息,读取
@autotest
、@uniPlatform
等信息来自定义生成的测试用例
第二步:生成测试用例
根据类型来定义测试应该如何生成:
tsinterface InputOptions { // 字符串填充数据 string?: string[]; // 数字填充数据 number?: number[]; // 布尔填充数据 boolean?: boolean[]; // any 填充数据 any?: { number?: boolean; string?: boolean; boolean?: boolean; object?: boolean; array?: boolean; null?: boolean; undefined?: boolean; }; object?: { // 填充可选属性 optional?: boolean; // 对属性可选值作笛卡尔积 product?: boolean; // 仅对相关属性作笛卡尔积 relation?: boolean; // 移除 undefined 属性值 removeUndefined?: boolean; }; // 生成的数组长度 array?: { min?: number; max?: number; }; // 联合类型最大生成个数 union?: number; } const defaultInputOptions = { string: ['', 'abc', '0', 'false', '文', '/', '%', ';'], // Number.MIN_SAFE_INTEGER, , Number.MAX_SAFE_INTEGER number: [-1.1, -1, -0.1, 0, 0.1, 1, 1.1, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], boolean: [false, true], any: { number: true, string: true, boolean: true, object: true, array: true, null: true, undefined: true, }, object: { optional: true, product: true, relation: false, removeUndefined: false, }, array: { min: 1, max: 1, }, union: Number.MAX_SAFE_INTEGER, };
根据第一步生成的
TypeData[]
和InputOptions
来生成测试用例。需要做到以下几点:- 分别根据类型和配置来生成数据
- 生成的数据要有一定的随机性
- 生成的数据要满足一定的边界条件限制
- 生成的数据要随机进行笛卡尔积组合(cartesianProduct)
- 要可以根据 jsdoc 中配置的 relation 关系来进行数据组合生成
第三步:生成测试用例文件
- 根据第二步生成的测试用例使用
@babel/template
来生成AST
数据 @babel/types
在生成AST
数据时填充具体的AST
结构- 使用
@babel/generator
和在AST
中填充数据生成具体的 code - 将 code 写入文件
总结
是一个很好的用来练手的项目。
- 可以学习到很多
AST
的知识。学会使用ts-morph
来处理 typescript AST,使用@babel/generator
、@babel/template
、@babel/types
来生成AST
- 熟练
jest
的使用 - 使用
rollup
配合@rollup/plugin-replace
、rollup-plugin-terser
、@rollup/plugin-commonjs
、rollup-plugin-typescript2
等将项目编译成npm
包 - 使用
argparse
来将打包的文件进行CLI
化
本文部分内容来自 ChatGPT、Github Copilot 自动生成