用例参数化
在做接口测试的时候,如果出现同一个接口或几个接口,接口的的入参字段相同,只是参数值不一样,那么这个时候写多个case就是冗余的,有没有什么速成的方法呢?有,此时我们想到了parameterized库,用参数化来实现
# 安装这个库
pip install nose-parameterized
什么是参数化,parameterized有什么用,相信你会有很多疑惑,接下来我们详解parameterized的使用。
parameterized是一个Python测试库,它允许你为单个测试方法提供多个参数集,从而避免编写多个几乎相同的测试方法。这通常用于数据驱动的测试场景,其中相同的测试逻辑需要在不同的输入数据上运行。
parameterized 库是 JUnit 的 Parameterized 测试类的 Python 版本,通常与 unittest 测试框架一起使用
官网示例:
代码运行后输出的结果展示:
代码实例:
import unittest
from parameterized import parameterized
class TestMyFunction(unittest.TestCase):
@parameterized.expand([
("test_case_1", 1, 2, 3), # 输入参数和预期结果
("test_case_2", "a", "b", "ab"),
("test_case_3", [1, 2], [3, 4], [1, 2, 3, 4])
])
def test_add(self, name, arg1, arg2, expected):
result = my_function(arg1, arg2)
self.assertEqual(result, expected)
用例读取与写入
项目测试脚本的生成采用上一节的参数化来完成,对两种文件类型进行参数化设计。首先excel文件我们模板如下:
参数化脚本代码文件名称为test_assignee.py代码如下:
import unittest
import paramunittest
import json
from commonsrc import common
from commonsrc.Log import MyLog
import readConfig as readConfig
from commonsrc import configHttp
import warnings
assigneeInfo_xls = common.get_xls("assignee.xls", "api")
localReadConfig = readConfig.ReadConfig()
localConfigHttp = configHttp.ConfigHttp()
proDir = readConfig.proDir
@paramunittest.parametrized(*assigneeInfo_xls)
class ProductInfo(unittest.TestCase):
def setParameters(self, No, api_name, HOST, request_url, method, request_data_type,request_data,return_data,check_data,result):
"""
set params
:return:
"""
self.No = No
self.api_name = api_name
self.HOST = str(HOST)
self.request_url = str(request_url)
self.method = method
self.request_data_type = request_data_type
self.request_data = request_data.encode('utf-8')
print(self.request_data)
self.return_data = None
self.result = None
def description(self):
"""
:return:
"""
self.api_name
def setUp(self):
"""
:return:
"""
self.log = MyLog.get_log()
self.logger = self.log.get_logger()
warnings.simplefilter("ignore", ResourceWarning)
def testGetProductInfo(self):
"""
test body
:return:
"""
localConfigHttp.set_url(self.HOST,self.request_url)
localConfigHttp.set_data(self.request_data)
if self.No !='No':
if self.method == 'get':
# get http
self.response = localConfigHttp.get()
self.info = json.loads(self.json_response)
print(self.info)
# check result
common.check_result(self.return_data, self.info)
else:
# post http
#response.setContentType("charset=utf-8”)
self.return_data = localConfigHttp.post()
if self.return_data["code"] == 0:
self.info = json.loads(self.json_response)
self.log.write_result(self.info)
# check result
#common.check_result(self.return_data, self.info)
#
else:
msg = self.return_data["msg"]
code = self.return_data["code"]
self.logger.debug(msg)
self.log.build_case_line(self.api_name,msg)
def tearDown(self):
"""
:return:
"""
self.log.build_end_line(self.api_name)
if __name__ == '__main__':
a = ProductInfo()
a.testGetProductInfo()
另外yaml的模板相对较为直观,如下:
参数化脚本代码文件名称为test_assignee_yaml.py代码如下:
import unittest
import paramunittest
import json
from commonsrc import common
from commonsrc.Log import MyLog
import readConfig as readConfig
from commonsrc import configHttp
from commonsrc import login
assigneeInfo_yaml = common.get_case_yaml("assignee.yaml")
localReadConfig = readConfig.ReadConfig()
localConfigHttp = configHttp.ConfigHttp()
proDir = readConfig.proDir
@paramunittest.parametrized(*assigneeInfo_yaml)
class ProductInfo(unittest.TestCase):
def setParameters(self, name, url, method, headers, json, result):
"""
set params
:return:
"""
self.name = str(name)
self.url = str(url)
self.method = str(method)
self.headers = headers
self.json = json
self.result = str(result)
self.return_data = None
self.info = None
def description(self):
"""
:return:
"""
self.name
def setUp(self):
"""
:return:
"""
self.log = MyLog.get_log()
self.logger = self.log.get_logger()
def testGetProductInfo(self):
"""
test body
:return:
"""
# set url
localConfigHttp.set_url(self.url)
if self.method == 'get':
# get http
localConfigHttp.set_params(params)
self.response = localConfigHttp.get()
self.info = json.loads(self.json)
print(self.info)
# check result
common.check_result(self.result, self.info)
else:
# post http
#response.setContentType("charset=utf-8”)
localConfigHttp.set_data(self.json)
self.return_data = localConfigHttp.post()
if self.return_data["code"] == 0:
self.info = json.loads(self.json)
print(self.info)
# check result
common.check_result(self.return_data, self.info)
#
else:
msg = self.return_data["msg"]
print("接口结果异常:",msg)
def tearDown(self):
"""
:return:
"""
self.log.build_end_line(self.name)
if __name__ == '__main__':
a = ProductInfo()
a.testGetProductInfo()
脚本调试方法
前面这节已经知道用例的参数化实现方法,实际调试代码的情况下我们可以控制excel的条数和excel名称达到我们调试的目的。但是细细看参数化脚本你会发现他的每个字段和格式基本是固定了,只适合大批量接口以及同一接口不同入参的批量测试。反之如果在实际项目中突然有一天项目出现了新的接口测试需求,且接口规则有所变化,如请求方式不再是post、get而是put,又或者说返回数据以及入参数据的格式不在是json,为了能快速的完成接口测试需求,就需要开辟新的测试脚本,重新参数化用例在之前的调用方法上新增格式、请求方式,此处不在累述。但是如果这些需求只是单单的改动了入参数据,比如需要用到文件入参,我们就可以使用unittest.TestSuit()这个测试套件,来实现单一脚本和多个脚本的测试
文章原创首发于微信公众号 软件测试微课堂,更多内容欢迎关注微信公众号查看