> 文档中心 > 接口测试框架开发实践3:用例管理模块

接口测试框架开发实践3:用例管理模块


本框架基于DDT原则,将测试数据和测试用例分离管理,测试数据模块通过yaml文件存储测试数据,测试用例则是测试场景的测试代码。每次执行测试用例,则会从测试数据文件中读取数据。

本文中测试用例是 测试数据(文件)+ 测试用例(文件)的统称。

正如上一篇文章介绍到用例管理介质有MySQL、Excel、Yaml/Json,也就是“线上存储”和“线下”存储方式。

本文介绍的框架利用yaml文件存储测试用例。

3.1 用例规范

无规矩不成方圆,规范有很多好处。

  1. 易读性高

  2. 易于批量生成测试用例等

  1. 维护成本低

测试用例文件命名规则

(1)测试用例遵循以下原则:

  • 文件名以 test_*.py 文件和*_test.py

  • 以  test_ 开头的函数

  • 以  Test 开头的类,不能包含 __init__ 方法

  • 以  test_ 开头的类里面的方法

  • 所有的包 pakege 必须要有__init__.py 文件

(2)测试用例文件的命名要突出测试功能,让别人一眼看到名字就能知道被测功能

例如:测试支付模块,则可以命名为test_payment_case_001.py

对于这块,一千个人心中可能有一千个哈姆雷特,核心原则就是 一眼能望穿功能 即可。

(3)测试数据文件命名规则

  1. 测试数据一般固定存档至固定文件夹下

  2. 文件命名要与测试逻辑文件有对应关系。

  3. 测试数据文件的名字建议全大写命名

  4. 测试数据可以根据测试要素拆分成:用例id, 用例HTTP部分,断言部分

3.2测试数据文件模板

在我的文章接口测试中也有详细的介绍,接口测试通常报告功能性测试、非功能性测试。

功能性测试主要涉及单接口测试、接口组合场景测试。

单接口测试主要围绕接口的参数、幂等展开;场景用例主要涉及多接口间的组合,更多涉及到接口间参数传递。

针对这两种不同的测试场景,我将测试数据模板分为两种:单接口、组合场景测试模板。

单接口测试数据模板

- case: 测试登陆001  http:    method: POST    path: https://account.xinli001.com/login    headers:      Content-Type: application/json; charset=UTF-8      X-Requested-With: XMLHttpRequest    body:      password: xxxxx      username: xxxxx@163.com  expected:    response:      message: 登陆成功    DB:    code: 0      - case: 测试登陆002  http:    method: POST    path: https://account.xinli001.com/login    headers:      Content-Type: application/json; charset=UTF-8      X-Requested-With: XMLHttpRequest    body:      password: xxxxx      username: xxxxx@163.com  expected:    response:      message: 登陆成功    DB:    code: 0

多接口组合测试数据模板

- case: 测试登陆查询回答内容001  http:    login:      method: POST      path: https://account.xinli001.com/login?next=https://www.xinli001.com/user      headers: Content-Type: application/json; charset=UTF-8 X-Requested-With: XMLHttpRequest      body: password: xxxxx      username: xxxxx@163.com    query:      method: GET      path: https://m.xinli001.com/get-my-answers.json      headers: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36      body: payload:  expected:    response:      message: 登录成功      code: 0

组合接口模板包含两条HTTP请求的数据,login和query接口的请求数据。

有了测试数据,下面就结合测试用例进行实践。

conftest.py

登陆前置动作,可以放置该文件中,作为setup使用。

#!/usr/bin/env python# -*- encoding: utf-8 -*-'''@Time    :   2021/06/20 12:07:09@Author  :   软件质量保障@wechat  :   ISTE1024@Email   :   byteflow@163.com@Blog    :   https://www.zhihu.com/people/iloverain1024@Copyright : 侵权必究'''import pytestimport yamlimport requests# 封装好的HTTP请求类class RequestHandler:    def __init__(self): """session管理器:维持会话,可以让我们在跨请求时保存某些参数""" self.session = requests.session()    def httpcore(self, method, url, params=None, data=None, json=None, headers=None, **kwargs): return self.session.request(method,url, params=params, data=data, json=json, headers=headers,**kwargs)    def close_session(self): """关闭session""" self.session.close()@pytest.fixture(scope='function')def login():    data = yaml.safe_load(open('/testcases/data/TEST_LOGIN.yaml', encoding='utf-8'))    http = data['http']    method = http["method"]    url = http["path"]    headers = http["headers"]    json = http["body"]['payload']    req = RequestHandler()    req.httpcore(method, url=url, headers=headers, data=json)    return req

登陆接口对应的测试数据文件为TEST_LOGIN.yaml

http:    method: POST    path: https://account.xinli001.com/login?next=https://www.xinli001.com/user    headers:      Content-Type: application/x-www-form-urlencoded; charset=UTF-8      X-Requested-With: XMLHttpRequest    body:      payload: password=xxxxx&username=xxxxxx%40163.comexpected:  response:    message: 登陆成功    code: 0

测试用例文件 test_function_002.py

#!/usr/bin/env python# -*- encoding: utf-8 -*-'''@Time    :   2021/06/20 12:07:09@Author  :   软件质量保障@wechat  :   ISTE1024@Email   :   byteflow@163.com@Blog    :   https://www.zhihu.com/people/iloverain1024@Copyright : 侵权必究'''import pytestimport yaml# 用例重载def data_reload(request, data_key):    data = request[data_key]    method = data["method"]    url = data["path"]    headers = data["headers"]    body = data["body"]    return method, url, headers, body# 用例集读取def get_test_data(test_data_path):    case = []  # 存储测试用例名称    http = []  # 存储请求对象    expected = []  # 存储预期结果    data = yaml.safe_load(open(test_data_path, encoding='utf-8'))    for td in data: case.append(td.get('case', '')) http.append(td.get('http', {})) expected.append(td.get('expected', {}))    parameters = zip(case, http, expected)    return list(parameters)@pytest.mark.parametrize("case, http, expected", get_test_data('/testcases/data/TEST_DATA_002.yaml'))def test_main(case, http, expected, login):    # 数据准备,这块可以再单独封装一层    method, url, headers, body = data_reload(http, 'query')    # 发起请求    query_res = login.httpcore(method, url=url, headers=headers, data=body)    print(query_res.json())    # 断言    assert query_res.json()['code'] == expected['response']['code']

对应的测试数据文件TEST_DATA_002.yaml

- case: 测试登陆查询回答内容001  http:    login:      method: POST      path: https://account.xinli001.com/login?next=https://www.xinli001.com/user      headers: Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest      body: payload: password=xxxx&username=xxxxx%40163.com    query:      method: GET      path: https://m.xinli001.com/get-my-answers.json      headers: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36      body: payload:  expected:    response:      message: 登录成功      code: 0

我们执行测试看一下效果:

3.3用例自动生成

测试用例自动化生成已经不算什么高深的技术了。作者在前东家工作时候就有过自动化用例生成的实践,并且有产出专利。我认为 用例生成的核心思想就是 数据源+用例模板化+模板引擎。正如上述我们介绍的单接口、组合接口模板,我们可以归类所有POST请求可以共用一套模板,所有GET请求可以共用一套模板,其他请求方法类似。当然亦可以汇总所有请求方法为同一个模板中;而数据源可以来源于POSTMAN导出的JSON文件、SWAGGER文档,Charles的Har文件,甚至JMeter的JMX文件,当然我们需要写解析这些文件的脚本才能获取到需要的数据。而模板引擎可以使用FreeMarker。

(1)测试数据生成

圈红处的可以作为变量值,从数据源中提取出来并填充到key键的值。

(2)测试用例生成

而测试用例文件中,上述圈红处可以作为变量,从数据源中提取需要的数据进行填充。

3.4用例维护

我们的自动化用例不是一成不变的,恰恰相反,自动化用例是需要经常维护更新的。这也是自动化用例的成本所在:维护成本。如果维护成本过高,那就不建议考虑着手自动化。而如何降低维护成本也是自动化测试需要重要关注的。

根据不同项目不同功能点,我们可以按以下维度实行用例管理。

(1)按组

(2)标签

(3)测试类型

而Pytest自身提供pytest.mark用于标记用例属性。详细介绍文档可以参考《Pytest系列(2)-Pytest指令详解》;具体实践如下:

配置pytest.ini文件:

[pytest]xfail_strict = trueaddopts=-vqs --html=./report.html;用例路径testpaths=./testcases;用例分组分类markers =    regression: 回归测试    smoke: 冒烟测试;日志相关配置log_cli = truelog_cli_level = INFOlog_cli_date_format = %Y-%m-%d %H:%M:%Slog_cli_format = %(asctime)s - %(filename)s - %(module)s - %(funcName)s - %(lineno)d - %(levelname)s - %(message)slog_file = ../logs/test.log

测试用例中使用分组markers(一个用例可以添加多个marker):

import pytest @pytest.mark.regressiondef test_01():    print('test01') @pytest.mark.smokedef test_02():    print('test02')@pytest.mark.skipdef test_03():    print('test03')

测试执行

pytest -m "分组名字"

往期推荐:

接口自动化测试框架实践1:接口测试概述

接口测试框架开发实践2:接口自动化测试框架设计思路

接口测试框架开发实践5:配置文件读取