强行为新项目写接口测试是一种什么样的体验
继续上次的话题,为新项目写ui自动化测试是一件非常有挑战的事情,写接口测试会不会容易一点呢?这次我就尝试了一下。
现阶段我们的管理端接口其实不多,就8个左右,所以从工作量上评估其实还可以。
测试策略
讲策略之前我们先看一下项目的简单业务属性。该项目的管理后台其实就是稍微复杂一点的增删改查。增加一条记录,编辑记录,各种组合条件查询记录,删除功能暂时没有,后面可能会跟进。
我的测试策略也很简单,首先搭建1个单独的测试环境,防止跟其他测试形式冲突,然后把最大的精力放在数据的准备和清理上。
- 准备数据:为了测试查询,比较好的方式是每次都先清空数据库,然后动态创建一些固定的数据,我指的固定是比如固定100条,每条的排序规则,各个字段都是确定的。
- 数据清理:完成测试后清空数据库,比如搜索测试完成之后清空数据库去测试创建和编辑,这样创建的时候就没有存量数据造成的断言干扰,就可以实现每次创建之前数据都是0条,创建成功之后变成1,这样断言就相对容易,而且用例能够以随机的顺序运行,减少了依赖;
代码实现
这里最有挑战的是数据准备和清理的代码实现,我需要准备下面的数据
- 通过接口创建一些数据到db,之所以用接口创建是因为一些联动的操作直接写db的话无法触发。我们的接口是http的,用python+requests就可以了,稍微麻烦的点是构造的数据需要通过接口的有效性校验,比如时间区间之类的,因为我们的服务会跑在多个不同的国家和地区,timezone也是需要关注的
- 把创建成功的数据id以及一些需要用到的字段存到redis里。我习惯于用redis的set,因为天生去重,并且可以使用
srandmember
来随机返回几条数据,在做查询校验的时候非常方便 - 查询一些关联表的信息或者需要用到的数据,保存在redis里。这里我用的是redis的string类型,需要保存的信息直接序列化成json字符串,非常的方便;
- 直接写sql做数据库的清理,直接调用es的resetful api做索引的清理。我们的查询使用的是es,所以清理数据的时候除了用sql去delete之外,es的index也是要清理的
- 使用配置文件来进行多环境多地区的配置,比如mysql每个地区的配置都不一样,同样的地区不同的业务数据也在不同的库里,把配置弄起来还是很有必要的
最终实现的效果是运行TEST_ENV=test REGION=cn python data_builder.py
这条命令之后就可以在对应的环境创建初始化数据了。代码比较啰嗦我就不粘贴了。
用例编写
用例编写无非是增删改查。
新增记录
- 测试各种边界条件,比如一些字段本来是必填的,就是任性不填。本来要求string类型结果传number类型等待
- 测试正常的情况,起码要把正常流程跑通
下面是一个例子
def test_ads_target_keyword_list_should_be_mandatory(valid_data_set):
del valid_data_set['target_keyword_list']
res = common_helpers.post_with_cookie("/create", valid_data_set)
common_assertion(res)
assert res['code'] != SUCCESS
assert 'required' in res['msg']
这里可以分享2点有意思的地方
- 返回值的错误码尽管可以枚举,但是逐一判断还是比较麻烦的,这里我就直接断言返回码不等于SUCCESS,SUCCESS其实可以看成是一个宏,所有用例里都统一
- 错误信息可以不需要精确判断,判断几个关键字是否存在就好了,比如上面例子里的required
编辑记录
- 从之前生成的记录里随机挑1条进行更新,因为我把所有初始化的记录id都存在了redis的set里,这一步其实就非常的自然了
- 测试各种边界情况,除了字段的合法性之外还要测试一些编辑特有的用例,比如只能编辑自己的记录
- 测试正常编辑成功的情况
搜索及查询
- 因为数据是提前生成好的,所以我们可以构造各种条件来进行断言,比如我就构造了10条active状态的记录,10条inactive的记录,按照状态来搜索时我可以直接断言,active就是10条,多一点少一点就是bug
- 构造多维度的搜索条件,这样覆盖面就更广一点,比如按A字段搜索,按B字段搜索,按A和B组合在一起搜索等
比如这个用例
def test_search_with_no_conditions():
page_size = 20
data = {
'filter': {},
'page_num': 1,
'page_size': page_size,
}
res = common_helpers.post_with_cookie(f"/action/search/list", data)
assert res['code'] == SUCCESS
assert len(res['data']['data']) == page_size
这里我没有传入任何条件,只判断了当前返回的数据条数必须等于page size,因为我之前创建了足够多的数据,所以这个用例是非常安全和稳定的
总结
- 最好有单独的测试环境
- 用配置文件来保存各个环境的配置,有配置中心更好,这样就不用改代码
- 在运行用例时通过环境变量来指定环境和地域,如果你的服务需要跑在多个国家和地区的话
- 每次都创建自己的测试数据集,这样断言起来会更加的容易
- 创建数据的脚本也可以用来进行ui自动化测试