继续上次的话题,为新项目写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自动化测试