# 简陋的全自动化测试实践


最近在搜广推项目里做了一些小小的基于数据驱动的测试尝试。

因为项目的特殊性，大部分的测试场景其实相对类似，大体可以分为下面几步

- 收集数据，整合成 1 个类似宽表的东西。比如在美团上给外卖投放一个关键字广告，那么投放之前需要收集这个商家的门店信息，比如门店名，经纬度；菜品信息，这个商家有哪些菜品，名字分别是什么；品牌信息，这个商家属于哪个品牌，品牌有哪些特殊属性；这些信息其实都分别在不同的业务表里，开发那边有离线数据流去打宽表，但是对于测试来说，如果不使用自动化的方式的话则需要用 sql 去查询，遇到有分表的情况则比较麻烦；
- 构造数据。还是外卖投关键字广告的例子，因为召回的规则和其他一些业务规则，我们投的关键字最好有相关性，比如商家的店名叫做“永久炸鸡”，那么投“炸鸡”这个关键字可能会比较好。所以通过上一步构造好的数据，从里面自动筛选出一些相关数据并进行构造也是必要的；
- 执行业务并进行断言。以搜索为例，收集数据阶段我们收集了很多的门店信息和菜品信息，那么使用门店名和菜品名进行搜索的话是需要有结果出来的，由于排序规则是算法团队去实现和测试的，所以我这边只需要数据可以搜出来就好，至于排序是什么样子，测试用例里面是不需要去关注的。

综合考虑了一下，我有一个大胆的想法。

上面这些步骤是不是都可以完全由自动化来实现？

### 使用爬虫进行数据收集

测试环境和体验环境我是有数据库权限的，所以可以通过 sql 来进行数据查询，逻辑其实很简单，从现有的数据里查一些拥有有效菜品的有效商家就好了，所以问题就简化成了使用脚本去连接数据库，然后进行一系列的连表查询就好了。不过因为菜品进行了分表，所以需要一些额外的逻辑去处理一下，不过总的来说还是不难的。

一切都很顺利，直到业务上线了以后，我发现我需要在线上去收集这些数据。因为安全策略的缘故，开发和测试都是没有线上数据库的访问权限的，因此我在非生产环境里通用的自动化脚本就成了一堆废纸。

后来有一天，我发现项目的本地测试人员都是在业务后台的各个功能模块里做数据的查询和准备，我突然有了使用爬虫去爬取数据的想法。

原理其实很简单，模拟业务后台的请求，通过后端暴露的 api 进行查询，最后想办法把数据组织好存储下来就行了。

后来用代码简单的实现了一下，效果其实还是不错的，而且完全不需要去顾虑分库分表问题，因为管理后台的 api 把这些都实现好了。这也让我开阔了一些思路，其实爬虫除了爬外部数据之外，还可以爬内部其他团队的数据，只要业务有管理后台，一切都好说。

### 使用 redis 进行数据存储

爬虫拉到数据之后，就需要对数据进行一些处理和存储。得益于业务 api 的杰出工作，之前查 sql 时候需要进行的数据处理现在就变得特别简单，因为业务逻辑都帮我都处理好了，下一步只需要把数据保存起来就好了。

因为数据需要反复使用和在多个场景下使用，所以存储对于我来说是必须的，但对于另一些场景，存储中间数据可能不是必选项。

因为对 redis 相对比较熟悉，所以我这里用 redis 实现了一些类似索引的东西。

- 用 set 去存储一些实体的主键，比如门店 id 和菜品 id 之类；
- 用 string 去存储详细信息，比如门店名，菜品的详细信息等；其中门店菜品之类的就直接用的 python dict 序列化成 json string，查询时候通过门店的 id 就可以直接拿到 json string，然后重新反序列化成 python 字典就好了

### 使用后端 api 进行数据创建

对于搜索来说组装好数据基本就可以测了，不过对于广告来说还需要进行广告的创建。这里我是直接调用 api 做创建，效率高而且不用去页面点。

### 使用 pytest 进行自动化测试

最后就是用例编写了，这里我直接用 pytest 实现了一些用例，贴一个具体例子。

```python
@pytest.fixture
def data():
	r = get_redis()
	k = r.srandmember(KEY_FOR_TEST)
	return json.loads(r.get(k))

def test_recall_by_full_store_name_success(data):
	sname = data['store_name']

	res = query_ads(sname, data['longitude'], data['latitude'])

	assert 'ids' in res, f"{sname} not recall"
	assert len(res['ids']) >= 1 # recall 1 record
```

这里用 fixture 来进行测试数据的获取，我准备了一批测试数据，每次随机返回 1 条，然后通过 redis 去拿具体数据，比如门店的经纬度信息和门店名。在用例里我判断了可以通过门店名进行召回，至于召回的数据排序是否正确，因为排序规则不属于我的测试范围，所以直接判断可以召回大于 1 条的数据就好了。

### 总结

目前看来这套框架在进行数据驱动的业务测试里还是效率很高的。而且由于爬虫突破了环境的限制，我还可以复用数据构造流程来进行很多的线上问题的排查工作。比如预先爬取线上当天的所有广告信息以及相关的门店菜品等基础信息，一旦线上用户反馈广告无法召回，直接调用调试工具进行重现和调试，问题复现和定位的速度加快了很多。

最关键的一点是，我实现了项目开始阶段那个有点大胆的想法：整体测试过程完全的自动化。尽管简陋，但是高效，测试开发比 1:11，无裁员之乱耳，无加班之之劳形。

