通常测试数据与功能函数分离,存储在功能函数的外部位置。在自动化测试运行时,数据驱动框架会读取数据源中的数据,把数据作为参数传递到功能函数中,并会根据数据的条数多次运行同一个功能函数。
而参数化就是将数据与业务分离,也可以理解成数据驱动,实现了参数化,能够通过不同数据得到不同用例,不仅方便测试人员修改、维护,同时也提升了代码可读性。而pytest中就有个功能可以很好的实现数据分离,那就是pytest.paramerize,类似于Unittest的DDT。
2、使用方法 (1)基本使用格式:@pytest.mark.parametrize('参数名',list)。既可以传单个数据也可以传多组数据,还可以传列表和字典类型的数据,如图。
# --*-- coding: utf-8 --*--
import pytest
class Test_Case:
@pytest.mark.parametrize('request_method', ['get', 'post', 'put'])
def test_case1(self, request_method):
print('请求方式为:', request_method)
@pytest.mark.parametrize('request_method, url, data', [('post', ['qiandu.com', 'jingxi.com'], {'username': 'admin', 'password': 'admin'})])
def test_case2(self, request_method, url, data):
print('请求方式为:', request_method)
print('目标url为:', url)
print('参数为:', data)
if __name__ == '__main__':
pytest.main(['./test_demo2.py::Test_Case', '-s'])
注意:当传入多组数据时,参数名称、实参、形参都要一一对应且不能多也不能少,否则会报错!
(2)parametrize--indirect除了传数据以外,parametrize还支持传入函数名来调用其他函数,只需要将indirect设为True即可。如下图所示,将indirect参数设为True之后,原本是普通变量的print_info就会当成函数并调用执行,而列表中实参的数据就会传入调用的print_info方法作参数了。
# --*-- coding: utf-8 --*--
import pytest
class Test_Case:
@pytest.fixture()
def print_info(self, request):
return '打印:' + request.param
@pytest.mark.parametrize('print_info', ['Jane', '21', 'girl'], indirect=True)
def test_case3(self, print_info):
print(print_info)
if __name__ == '__main__':
pytest.main(['./test_demo2.py::Test_Case::test_case3', '-s'])
3、结合外部文件
在使用pytest做接口自动化测试中,我们虽然可以使用parametrize来传入数据实现参数化,但数据量多大时,我们不可能在每条用例都输入所需的数据,这大大提高了维护成本、降低用例复用性,还是不够方便,所以我们可以结合yaml、txt、xml等文件来集中管理测试数据。
我们以json文件为例(不同文件的读写操作不同,在此不做多延伸),先写一个json文件读取方法read_json。将获取到的数据整理成我们想要的格式后,就可以通过parametrize传入了。
# --*-- coding: utf-8 --*--
import json
import jsonpath
import pytest
def read_json():
username_list = []
password_list = []
with open("../config/login_file.json", "r") as f:
fp = json.loads(f.read())
for i in fp['user_list']:
username_list.append(i['username'])
password_list.append(i['password'])
return username_list, password_list
@pytest.mark.parametrize('login_data', read_json())
def test_case4(login_data):
print(login_data)
if __name__ == '__main__':
pytest.main(['./test_demo2.py::test_case4', '-s'])
json文件中的数据:
{
"user_list": [
{
"username": "admin",
"password": "admin"
},
{
"username": "root",
"password": "root123"
},
{
"username": "user",
"password": "123456"
}
]
}
结果如下图:
由此我们就可以把所有需要的数据都存放在文件中集中管理,无需在特定用例中更改特定数据,这样就减少了用例的维护成本。
在此基础上,我们再稍微升华一下,通过pytest+json+request来实现接口自动化测试
# --*-- coding: utf-8 --*--
import json
import pytest
import requests
def read_json():
with open("../config/login_file.json", "r") as f:
fp = json.loads(f.read())
data_list, api_data = [], {}
for i in fp['login_api']:
if i['method'] != 'get':
api_data['param'] = i['param']
api_data = {
'method': i['method'],
'url': i['url'],
'headers': i['headers']
}
data_list.append(api_data)
api_data = {}
return data_list
def send_request(method, url, headers, param):
return getattr(requests, method)(url=url, headers=headers, param=param)
@pytest.mark.parametrize('login_data', [read_json()])
def test_case4(login_data):
for i in login_data:
response = send_request(method=i['method'], url=i['url'], headers=i['headers'], param=i['param'])
print('状态码:', response.status_code)
print('返回数据:', response.text)
if __name__ == '__main__':
pytest.main(['./test_demo2.py::test_case4', '-s'])
json文件存放的数据:
{
"login_api": [
{
"method": "get",
"url": "www.qiandu.com",
"headers": "token=**12cv45, session=CXFE*sgf="
},
{
"method": "post",
"url": "www.jingxi.com",
"param": {
"username": "admin",
"password": "admin"
},
"headers": "token=**12cv45, session=CXFE*sgf="
},
{
"method": "get",
"url": "www.tiangou.com",
"headers": "token=**12cv45, session=CXFE*sgf="
}
]
}



