接口自动化做了几年,踩过最多的坑不是框架选型,不是断言写法,而是测试数据的构造。很多项目自动化用例写了一大堆,跑起来全是红的,一看日志全是数据问题——要么订单状态不对,要么token过期,要么关联数据被之前跑的用例污染了。今天就把我在接口自动化测试里数据构造的整套思路和实操方法整理出来,从最简单的静态数据到复杂的业务状态数据、加密数据、异步回调数据,一次性说清楚。
1. 接口测试数据构造的整体思路与设计原则
1.1 数据构造在接口自动化中的定位
接口自动化测试的核心是验证接口在不同输入下的行为是否符合预期,而数据构造就是给接口准备合适的输入。很多测试新手会把数据构造简单理解为"在代码里写死几个参数",实际远远不够。一个完整的接口自动化用例执行链路通常是:准备数据 → 发送请求 → 断言响应 → 清理数据,数据构造贯穿始终,直接决定用例的稳定性、可维护性和执行效率。
我在团队里做过一次统计,自动化用例失败原因里,数据相关问题占了将近四成。不是说接口本身有bug,而是测试数据过期了、被并发用例抢占了、状态没有重置、关联数据被删了。这些问题如果不在数据构造环节提前设计好,后面跑用例会越跑越痛。
1.2 数据构造的四条核心原则
独立性原则。一条用例的数据不依赖其他用例的执行结果。比如测试"创建订单"接口,就不要依赖"登录接口"返回的token作为前置条件,而是通过数据准备阶段直接构造一个有效的登录态,或者用测试环境专用token。
可重复性原则。同一套数据可以在任意时刻重复执行而不互相干扰。最典型的坑是用了固定的手机号注册用户,第一次跑通了,第二次跑就报"用户已存在"。解决办法是动态生成唯一标识,例如手机号用时间戳拼接,用户名用UUID。
真实性原则。数据要尽量贴近生产环境的真实形态。长度、格式、编码、边界值都要符合实际业务规则。我之前见过有人测手机号校验,测试数据写的是"12345678901",根本不符合11位号码规则,连真实场景都没覆盖到。
可清理原则。用例执行完成后,数据要能恢复原状或者被标记清理,否则脏数据越积越多,最终导致测试环境不可用。
注意:一条好的测试数据,不只是让当前用例跑通,还要保证下一轮执行还能继续用。设计阶段多想一步,执行阶段能少加一个月的班。
1.3 数据构造的三种来源与选型对比
| 数据来源 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 静态数据文件 | 参数固定、枚举类数据、配置类数据 | 简单直观、易于Review | 灵活性差,无法覆盖动态场景 |
| 代码动态生成 | 时间戳、随机数、唯一标识、边界值 | 覆盖率高、可重复执行 | 需要维护生成逻辑 |
| 数据库直接构造 | 业务状态类数据(订单、用户、流水) | 效率高、状态可控 | 绕过接口逻辑,可能造出非法数据 |
| Mock服务数据 | 第三方接口、外部依赖、异常响应 | 隔离依赖、稳定可控 | 需要维护Mock服务,增加架构复杂度 |
实际项目中基本是这四种混用。我的建议是:能用代码动态生成的就用代码,需要状态流转的走数据库构造,第三方依赖一律Mock,静态配置类数据用文件维护。关键是建立统一的数据构造入口,不要让每条用例自己去"自由发挥"。
2. 接口测试数据构造的核心实操方法
2.1 数据库直接构造法:状态数据的最优解
接口自动化里最难的其实是"业务状态"的构造。比如测试一个"已发货订单的物流查询接口",你需要订单表里有条记录,状态是已发货,还要有对应的物流单号。如果靠跑接口把订单一步步推到已发货状态,中间要支付、要回调、要审核,少说也是三四次接口调用,稳定性还差——任何一步失败,后面的用例全挂。
数据库直接构造就是绕开中间步骤,直接在库里边把数据插成目标状态。我在项目中常用的是SQL构造,配合专属的测试账号体系。
-- 构造一个已发货状态的订单 INSERT INTO t_order ( order_id, user_id, order_status, pay_status, ship_status, logistics_no, create_time, update_time ) VALUES ( 'T20240115001', 'U10086', 'SHIPPED', 'PAID', 'SHIPPED', 'SF1234567890', NOW(), NOW() ); -- 构造对应的订单商品明细 INSERT INTO t_order_item ( item_id, order_id, sku_id, sku_name, price, qty ) VALUES ( 'I20240115001', 'T20240115001', 'SKU888', '测试商品A', 9999, 1 );这里有几个细节需要注意:
自增主键和外键关联。直接插入数据时,主键ID要么指定一个明确的唯一值,要么插入后再查出来用。关联表的外键要保持一致,不能订单表里写了order_id,明细表里忘了写。
状态字段的枚举值要查字典。不同团队的订单状态定义不一样,有的是数字(0待支付、1已支付、2已发货),有的是字符串('PENDING'、'PAID'、'SHIPPED'),插入前务必去状态字典表里确认,否则构造出来的数据接口根本识别不了。
时间字段的处理。很多接口会用时间做排序或者过滤,插入数据时时间字段尽量用NOW(),或者相对于当前时间做偏移计算,避免写死时间导致用例越跑越"过期"。
数据库构造要封装成工具方法,不要直接在用例里写SQL。我在Java项目里一般会封装一个DataFactory工具类,把常用数据构造场景都做成方法,比如createOrder(String status)、createUser(String tag),用例里只需要一行调用。
public class OrderDataFactory { public static String createOrder(String status) { String orderId = "T" + System.currentTimeMillis(); String sql = "INSERT INTO t_order (order_id, user_id, order_status, pay_status, ship_status, logistics_no, create_time, update_time) " + "VALUES ('" + orderId + "', 'U10086', '" + status + "', 'PAID', '" + status + "', 'SF" + System.currentTimeMillis() + "', NOW(), NOW())"; DbUtil.execute(sql); return orderId; } }2.2 接口调用关联法:上下文数据怎么串联
有些场景下,数据库直接构造反而麻烦,不如走正常的接口逻辑去拿数据。最典型的就是token和登录态。登录接口涉及密码加密、会话管理,直接在库里造token很容易造出个不能用的,因为服务端的内存或者Redis里没有对应的session。
接口调用关联法的思路是:前置接口的返回值,作为后续接口的数据输入。这里推荐把关联数据缓存到上下文中,而不是每条用例各取各的。
我之前见过不少项目的做法是:在登录用例里把token存在一个静态变量里,后面的用例直接引用。这在单线程跑用例时没问题,但一旦上了并发执行,多个线程同时改静态变量,token就乱了,有的用例拿到别人的token,直接401。
正确做法是用ThreadLocal或者测试框架自带的上下文存储机制。Java里TestNG有ITestContext,JUnit 5有TestInfo,也可以自己封装一个简单的线程上下文。
public class TestContext { private static final ThreadLocal<Map<String, Object>> CONTEXT = new ThreadLocal<>(); public static void set(String key, Object value) { if (CONTEXT.get() == null) { CONTEXT.set(new HashMap<>()); } CONTEXT.get().put(key, value); } public static Object get(String key) { return CONTEXT.get() == null ? null : CONTEXT.get().get(key); } public static String getToken() { return String.valueOf(get("token")); } }接口关联的第二个典型场景是"刚创建的资源ID"。例如测试"查询商品详情"接口,需要先调用"创建商品"接口拿到商品ID,再把商品ID传给查询接口。这类数据构造的关键是把握好依赖关系,在用例里显式声明数据依赖,而不是隐式假设之前某条用例执行过。
2.3 Mock数据构造:第三方依赖和异常场景怎么破
接口自动化最怕的是被测系统依赖的第三方接口不稳定。比如你测下单接口,下单要调支付网关,支付网关是第三方团队的,他们测试环境关掉了,你的自动化用例也跟着全挂。
Mock数据构造就是把第三方依赖接口用本地Mock服务替代,保证被测系统的依赖是可预测、可控制的。
我在实践中常用两种方案:
方案一:基于WireMock的独立Mock服务。启动一个WireMock服务,预定义好第三方接口的请求匹配规则和响应模板。被测系统在测试环境的第三方接口地址指向这个Mock服务。
// WireMock 配置示例 public class PayGatewayMock { public static void configure() { WireMock.configureFor("localhost", 8081); WireMock.stubFor(WireMock.post(WireMock.urlEqualTo("/api/pay/create")) .willReturn(WireMock.aResponse() .withStatus(200) .withHeader("Content-Type", "application/json") .withBody("{\"code\":\"SUCCESS\",\"transactionId\":\"MOCKTX20240115001\"}"))); } }方案二:框架内嵌Mock。在测试框架里用Mockito之类的工具直接Mock掉内部依赖的Client类。这种方式适合单元级别的接口测试,但做端到端的接口自动化时不够真实,不推荐作为主方案。
Mock数据构造的另一个价值是模拟异常场景。真实第三方接口很难触发"超时""返回格式错误""签名错误"这类异常,用Mock可以轻松做到。比如测试下单接口在支付网关返回"余额不足"时的处理逻辑,Mock直接返回对应响应体就行。
心得:Mock数据一定不能只在本地生效,测试环境的公共Mock服务要纳入代码管理,随项目版本一起发布。我吃过一次亏,Mock服务是同事手动启动的,人一离职服务就没人管了,自动化直接瘫了三天。
2.4 加解密与签名数据的构造:处理"看不见的"数据
接口测试里有一类让人头疼的数据:加密字段和签名参数。很多金融、支付类接口,请求体里的关键字段是加密传输的,接口还要校验签名。这类数据没法直接"想传什么就传什么",得严格按照服务端的加密规则来构造。
对称加密数据的构造。常见的有AES、DES、SM4。构造方式是在测试工具类里实现同样的加密算法和密钥。这里有坑:同一个算法不同的工作模式(ECB、CBC)、填充方式(PKCS5Padding、PKCS7Padding)、初始向量(IV)设置,加密结果都不一样。构造数据和对接联调时,先确认好服务端用的具体参数。
// AES-CBC 加密工具示例 public class AesUtil { private static final String KEY = "abc123def456ghi7"; private static final String IV = "1234567890abcdef"; public static String encrypt(String plainText) { try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES"); IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8)); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new RuntimeException("AES加密失败", e); } } }非对称加密和签名的构造。RSA加密、MD5签名、SHA256WithRSA签名这类场景,测试环境一般会提供测试密钥对。公钥私钥都要拿到,公钥用来构造加密数据,私钥用来生成签名。构造签名时要注意参与签名的字段顺序、拼接规则,这些细节在接口文档里通常会写。
标准化的处理方案。我建议把加解密、签名、验签的逻辑统一封装成一个SignUtil工具类,在数据构造层直接调用。不要在每条用例里重复写加密逻辑,否则一旦密钥轮换或者算法调整,全票都要改。
2.5 外部文件数据构造:Excel、JSON、CSV怎么用
有些接口的测试数据天然是结构化的,比如配置类接口、批处理导入类接口。把这类数据维护在代码里反而不直观,用外部文件配合数据驱动框架更合适。
JSON文件构造。适合请求体比较复杂、嵌套层次深的接口。比如一个创建合同的接口,请求体有合同主体、合同条款、签署方列表等多层嵌套,直接在Java代码里拼JSON可读性太差。用JSON文件维护,每个用例一个文件,逻辑清晰,也方便产品和开发一起Review。
{ "contractName": "采购合同-20240115", "contractType": "PURCHASE", "parties": [ { "partyName": "甲方公司", "partyType": "BUYER", "contactPhone": "13800138000" }, { "partyName": "乙方公司", "partyType": "SELLER", "contactPhone": "13900139000" } ], "effectiveDate": "2024-01-15", "expireDate": "2025-01-14" }Excel数据驱动构造。Excel强在参数化组合。我的Excel数据驱动表格通常是这样的格式:
| 用例编号 | 接口名称 | 请求参数(data字段) | 期望结果 |
|---|---|---|---|
| TC001 | 创建用户 | {"name":"Tom","age":18} | code:0 |
| TC002 | 创建用户 | {"name":"Tom","age":200} | code:1001 |
框架读取Excel后,把每行的参数传给对应的测试方法。这样测试用例的增删改只需要改Excel,不需要动代码,测试同学自己就能维护用例。
注意:外部文件数据构造非常适合数据驱动,但文件维护要防"漂移"。项目迭代过程中接口字段调整,文件里的用例数据很容易过期。建议在CI里加一道检查,接口字段变更时提示数据文件同步更新。
3. 框架层的数据构造实现:Java接口自动化框架实操
3.1 框架核心组件与数据准备层的设计
基于Java的接口自动化框架,数据构造不是零散的几条SQL、几个工具类,而是要有清晰的分层设计。我实践中推荐的分层是这样的:
| 分层 | 职责 | 典型组件 |
|---|---|---|
| 测试用例层 | 描述业务场景、步骤和断言 | TestNG/JUnit测试类 |
| 数据构造层 | 统一提供测试数据 | DataFactory、SqlHelper、MockClient |
| 请求执行层 | 发起HTTP请求、处理响应 | RestAssured、OkHttp、HttpClient |
| 基础设施层 | 环境配置、日志、报告 | Yaml配置、Log4j2、Allure |
数据构造层这里有几个必须做的事情:
统一入口。对外暴露的方法名要语义化,让用例层代码可读性好。比如createUserWithBalance(Long amount)就比executeInsert("insert into user...")直观得多。
数据隔离。不同业务线的测试数据要加标识,防止互相干扰。我习惯在表里加test_tag字段,每次插入数据打上当前跑批的标识(比如跑批时间戳),清理数据时按标识批量删。
数据自动清理。用例执行完之后的清理逻辑,要放在框架的afterTest或者@AfterMethod钩子里,不要依赖每条用例自己写。框架层面统一清理,才能保证漏网数据不会残留。
3.2 动态参数生成:时间戳、随机数和唯一标识
接口自动化里,动态参数是最常被用到的数据构造方式。写死的数据跑一次两次没问题,跑多了就撞数据。动态化生成的核心是保证唯一性和格式合法性。
我常用的动态参数生成能力清单:
- 时间戳:
System.currentTimeMillis(),适合拼接到用户名、手机号、订单号后边。 - 日期格式化:
new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()),适合生成业务单号。 - UUID:
UUID.randomUUID().toString().replace("-", ""),适合做唯一标识。 - 随机数:
ThreadLocalRandom.current().nextInt(min, max),适合构造金额、数量、年龄等业务字段。 - 手机号:
"138" + String.format("%08d", System.currentTimeMillis() % 100000000),注意不要撞真实用户号码。
实际项目中,我会把这些能力统一封装成一个DataGenerator类:
public class DataGenerator { public static String getUniquePhone() { return "138" + String.format("%08d", System.currentTimeMillis() % 100000000); } public static String getUniqueUserName() { return "user_" + System.currentTimeMillis(); } public static String getOrderNo() { return "ORD" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()); } }构造动态参数时有个小技巧:边界值和异常值不要动态化。比如测试金额字段的上限、年龄字段的负数,这些值必须是确定的,动态化会导致断言没法写。动态参数只用在"需要唯一但不需要特定值"的场景。
3.3 测试数据模板与YAML配置化管理
框架里维护数据的方式,我最推荐的是YAML文件。相比Java代码里拼字符串、相比JSON文件,YAML的可读性和灵活性都更好,还能天然支持注释。
看一个YAML数据配置的示例:
user: admin: name: "admin_user" password: "123456" role: "ADMIN" normal: name: "normal_user" password: "123456" role: "USER" order: status: pending: "PENDING" paid: "PAID" shipped: "SHIPPED" closed: "CLOSED" amount: max: 999999.99 min: 0.01 zero: 0.00 negative: -100框架启动时加载YAML配置,数据构造层通过key取值。这样测试数据从代码中剥离出来,环境差异(测试环境、预发环境的数据可能不同)也只在YAML里体现,不用改Java代码。
做数据配置化时,有两点要克制:
第一,不要什么数据都放进YAML。频繁变化的、明显是计算结果的、依赖时间戳的,只在代码里生成。YAML只放稳定的、用于区分场景的基准数据。
第二,环境切换的数据隔离要做好。我见过最受伤的情况是测试环境的数据配成了预发环境的账号,接口调用全跑预发环境去了,还把预发的测试订单都给打乱了。YAML文件建议按环境拆分:application-test.yaml、application-pre.yaml,框架启动时通过profile选择加载。
3.4 数据工厂模式:把数据准备抽象成"生产线"
Java框架里数据构造要做到好维护,关键是学会用工厂模式来组织代码。不是简单地把造数SQL封装成方法,而是把"业务数据的正常态、边界态、异常态"都抽象成可复用、可组合的生成逻辑。
我举一个用户体系的数据工厂示例:
public class UserDataFactory { public static User createNormalUser() { return User.builder() .name(DataGenerator.getUniqueUserName()) .phone(DataGenerator.getUniquePhone()) .status(UserStatus.ACTIVE) .build(); } public static User createFrozenUser() { return User.builder() .name(DataGenerator.getUniqueUserName()) .phone(DataGenerator.getUniquePhone()) .status(UserStatus.FROZEN) .build(); } public static User createUserWithBalance(long amount) { User user = createNormalUser(); user.setBalance(amount); return user; } }这里的核心设计思路是:用构造器方法名表达数据语义,调用方不需要关心数据是怎么造出来的,只需要表达"我要一个冻结用户""我要一个余额为xxx的用户"。工厂方法内部可以自由切换构造方式——今天走数据库插入,明天改成调接口注册,调用方代码完全不用动。
心得:数据工厂设计得好不好,直接决定测试用例的代码量。我见过最多的情况是一条用例里十几行代码全在造数据,真正的请求和断言只有三五行,这明显就是数据工厂没做好。好的数据工厂应该让用例代码精简到"准备、操作、断言"三段式结构。
4. 数据构造的高阶姿势:批量、异步与真实感
4.1 批量数据构造与性能考虑
有些接口测试要用到批量数据,比如分页查询接口要测试列表在不同数据量下的表现,需要一次性造几千甚至几万条记录。逐条insert显然不现实,得用批量操作。
MySQL批量插入的效率比逐条插入高一个数量级。我用的是JDBC批处理:
public static void batchInsertOrders(int count) { String sql = "INSERT INTO t_order (order_id, user_id, order_status, create_time) VALUES (?, ?, 'PENDING', NOW())"; try (Connection conn = DbUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { for (int i = 0; i < count; i++) { ps.setString(1, "T" + System.currentTimeMillis() + "_" + i); ps.setString(2, "U10086"); ps.addBatch(); if (i % 500 == 0) { ps.executeBatch(); } } ps.executeBatch(); } catch (SQLException e) { throw new RuntimeException("批量造数失败", e); } }批量造数的另外一个坑是环境性能。测试环境数据库一般比较弱,一次性插入太多数据可能把数据库拖垮,影响其他测试。我的经验是:批量造数控制在能支撑测试需求的最小量级,不要一上来就追求五位数。
4.2 业务规则复杂时的数据依赖链构造
电商业务里有一个经典的复杂数据场景:下单成功依赖用户、商品、库存、优惠券、收货地址等多个数据实体。这类场景的数据构造核心在于"数据依赖链"要完整。
我之前构造过一个"使用优惠券下单"的数据依赖链,拆解下来包含:
- 创建用户并保证余额充足;
- 创建商品并配置价格;
- 创建库存记录并扣减一部分库存;
- 创建一个满足条件的优惠券并绑定到用户;
- 构造用户的默认收货地址。
如果按接口调用的顺序去准备这些数据,每次下单都要跑六七个接口,用例效率极低。数据工厂的做法是把整条链封装成一个"下单准备"方法,内部直接操作数据库把依赖数据一次性构造好,下单接口只需要传几个关键参数。
public static OrderContext prepareOrderWithCoupon() { User user = UserDataFactory.createNormalUser(); Product product = ProductDataFactory.createProduct(); StockDataFactory.createStock(product.getId(), 100); CouponDataFactory.createCoupon(user.getId(), 10, 100); AddressDataFactory.createDefaultAddress(user.getId()); return new OrderContext(user, product); }这种"压缩数据准备路径"的设计,是接口自动化从"能跑"到"能高效稳定跑"的关键一步。
4.3 异步回调与状态流转数据怎么构造
支付、退款、发货这类业务涉及异步处理。你调了下单接口,系统返回"处理中",真正状态变更要等支付回调触达。测试这类接口,数据构造要能模拟异步回调事件。
常用的做法是在测试环境预留一个"模拟回调"接口,测试用例直接触发这个接口来推进业务流程。如果业务系统没有预留类似的测试后门,就要考虑通过数据库层面模拟"回调已完成"后的数据结果。
另外还有一个思路是直接测试回调接口本身。支付回调本质也是一个HTTP接口,把回调的请求体当作测试数据构造的输入,验证回调处理逻辑的正确性。这时候数据构造的关键在于把回调通知报文的各种可能形态都构造出来,包括正常通知、重复通知、签名错误通知、金额不一致通知等。
5. 常见数据构造问题与排查技巧实录
5.1 案例一:用例反复跑失败,因为脏数据没清理
团队里曾经有个"创建优惠券"的用例,第一次跑是绿的,第二次跑就红了。排查下来发现是代码里构造数据用的优惠券编码是写死的,第一次插入成功,第二次触发唯一索引冲突。
这类问题的排查思路很简单:查看数据库里是否存在上一次跑批残留的数据。根因是清理逻辑缺失。解决方案:用例的@AfterMethod加上清理动作,同时把优惠券编码改成动态生成。
排查时可以用一个辅助SQL快速确认脏数据:
-- 查看测试标识为20240115的数据残留 SELECT * FROM t_coupon WHERE test_tag = '20240115';5.2 案例二:登录态并发冲突导致用例间歇性失败
前面提到的ThreadLocal上下文,就是从这个坑里趟出来的。当时框架里用了一个全局静态变量存token,单线程时稳如老狗,一开并行执行就大量401。
排查过程:先看失败日志,发现401比例和并行度强相关;接着对比并行和串行执行时的token取值,确认是token相互覆盖。换成ThreadLocal + TestNG的ITestContext存储token后,问题消失。
这里提醒一下:用TestNG做并行执行时,上下文存储一定要保证线程隔离,不要为了图省事用static变量。
5.3 案例三:Mock数据不生效,接口仍请求真实第三方
有同事配置了WireMock,本地启动也正常,但被测接口还是请求到了真实第三方地址。排查后发现是测试环境的第三方地址配置在Nacos上,本地WireMock只是改了本地hosts文件,被测服务部署在测试环境,请求根本不会到本地来。
正确做法:Mock服务要部署在和被测服务同一套测试环境中,通过配置中心或环境变量把第三方地址切换到Mock服务地址。这一点在前期基建时就要想清楚,Mock服务要当成项目的一等公民来部署。
5.4 高频问题速查表
| 问题现象 | 可能原因 | 排查与解决 |
|---|---|---|
| 用例第一次通过,第二次失败 | 唯一索引冲突/脏数据 | 检查数据残留,造数加动态标识 |
| 偶发401/登录态失效 | token并发覆盖/过期 | 用ThreadLocal隔离上下文,检查token有效期 |
| 数据造出来了但接口查不到 | 事务未提交/连错库 | 检查造数连接的事务和数据库配置 |
| 接口报数据状态不合法 | 枚举值/状态流转不对 | 查状态字典表,用正确的数据创建方法 |
| Mock接口返回正常但业务异常 | Mock响应格式与真实不符 | 对比真实接口报文,调整Mock的response模板 |
| 批量造数很慢 | 逐条insert/索引过多 | 改JDBC批处理,临时禁用非必要索引 |
| 时间字段导致数据"过期" | 时间写死 | 改用NOW()或相对时间偏移 |
5.5 提高排查效率的辅助手段
数据构造问题排查最耗时的是"看数据"。我建议在框架里内置两个能力:
数据可视化查询。提供一个简单的数据查询入口,用例执行失败时,可以直接查看到当前测试数据在数据库里的实际状态。不一定要做UI,命令行工具或者一个查询接口都行。
数据链路日志。每次数据构造都打日志,记录造了哪些数据、SQL是什么、耗时多久。我曾经通过日志发现一个造数方法跑了三秒,优化SQL后直接降到两百毫秒,整个用例集执行时间缩短了一截。
写在最后的经验
做接口自动化这几年,数据构造从最开始"随手写几个参数",到后来形成一套完整的方法论,最大的体会是:数据构造不是测试用例的附属品,它本身就是一个需要专门设计的工程问题。数据准备得好,自动化用例跑起来又快又稳;数据准备得差,框架再牛也会被数据问题拖死。
如果你正在搭接口自动化的架子,我建议从第一天就把数据构造当成一等公民来设计——确定数据来源、封装数据工厂、建立清理机制、规划数据隔离。这些东西越往后补,成本越高。另外,数据构造方法没有银弹,不同业务、不同团队、不同环境,适合的方案都不一样,拿我这套思路去对照你的实际场景,裁剪出最适合自己团队的路线就好。