TA的每日心情 | 无聊 4 天前 |
---|
签到天数: 1050 天 连续签到: 1 天 [LV.10]测试总司令
|
I.TestCase作用:是最小的测试单元,用于检查特定输入集合的特定返回值,可以用来创建新的测试用例
II.编写测试用例规则
(1)创建一个测试类,必须继承unnittest模块的TestCase类
(2)创建一个测试方法,必须以"test"开头
(3)调用被测试类,传入初始化数据
(4)调用被测试方法,得到计算结果。用assertEqual()断言是否与预期结果相同。
(5)调用unnitest的main()执行测试用例
- .:一条运行通过的测试用例
- F:一条运行失败的测试用例
- E:一条运行错误的测试用例
- s:一条运行跳过的测试用例
复制代码 III.定义测试方法:以test 开头的方法就是一条测试用例 (1)准备用例数据:用例的参数(datas)和预期结果(excepted)
(2)执行功能函数,获取实际结果:result = res['code']
(3)对比实际结果和预期结果:self.assertEqual(excepted, result)【用例执行通没通过的评判标准:断言异常】
IV.测试用例包含内容
(1)数据处理
·读取excel数据
·数据驱动:ddt方法
·替换excel数据:header加token,可变数据替换(正则替换)
·excel数据格式处理:比如str转json-->eval,编号str转为int
(2)错误写入日志
(3)执行结果和对比结果写入excel
(4)查询[url=]数据库[/url]结果
完整代码:
- import os
- import unittest
- from library.ddt import ddt,data # ddt数据驱动
- from com.doexcel import DoExcel # 操作excel数据
- from com.contants import DATA_DIR # 测试用例模块所在目录
- from com.myconf import conf #读取配置文件
- from com.log import my_log # 日志处理对象
- from com.handle_data import Header,replace_data,TestData # 数据处理
- from com.handle_request import HandleRequest # http请求方法
- from com.mysql import MySql # 导入数据库
- excel_path = os.path.join(DATA_DIR,"testexcel.xlsx") # excel路径
- @ddt
- class TestClassName(unittest.TestCase):
- excel = DoExcel(excel_path, "register")
- cases = excel.read_data() # 读取excel数据
- http = HandleRequest() # 创建http请求对象
- mysql = MySql() # 创建数据库对象
- @classmethod
- def setUpClass(cls):
- my_log.info("---------------开始执行TestClassName类测试用例---------")
- def setUp(self):
- pass
- # 每条用例执行之前都会执行
- @data(*cases)
- def test_methodName(self,case):
- # -----------------------第一步:准备用例数据-------------------------------------
- # 用例方法参数
- # 请求url
- url = conf.get('url_info', 'url_base')+ case["url"]
- # 请求方法
- method = case["method"]
- # 数据替换
- case['data'] = replace_data(case['data'])
- # excel中读的数据类型str转为json
- data = eval(case["data"])
- # 请求头
- headers = getattr(Header, 'headers')
- # 将token加到请求头中
- headers['Authorization'] = getattr(TestData, 'token')
- # 预期结果
- expected = eval(case['expected'])
- # 该用例在表单中所在行
- row = int(case['case_id']) + 1
- #-----------------------第二步:发送请求到接口,获取实际结果-------------------------------------
- result = self.http.send(url = url,method = method,json = data,headers = headers).json()
- TestResult = 'FAIL' # 测试对比结果:默认为失败
- try:
- self.assertEqual(expected ['code'], result['code'])
- TestResult = 'PASS'
- my_log.info("执行用例:{0}--->执行通过".format(case["title"])) # 将测试结果写入日志文件
- except AssertionError as e:
- my_log.info("执行用例:{0}--->未执行通过,出错位置为:{1}".format(case["title"], e)) # 将测试报错结果写入日志文件
- raise e
- finally:
- self.excel.write_data(row = row, column = 9,value = str(result)) # 回写执行结果
- self.excel.write_data(row = row,column = 9,value = TestResult) # 回写比对结果
- def tearDown(self):
- pass
- # 每条用例执行之后都会执行
- @classmethod
- def tearDownClass(cls):
- my_log.info("---------------结束执行TestClassName类测试用例---------")
- if __name__ == '__main__':
- unittest.main()
复制代码
说明:
·配置文件涉及内容:
- [url_info]
- url_base = url
- content-type = application/json; charset=UTF-8
- [test_info]
- ....
复制代码 ·ddt实现接口报告中按接口名显示用例(修改ddt中的mk_test_name())
- def mk_test_name(name, value, index=0):
- """
- Generate a new name for a test case.
-
- It will take the original test name and append an ordinal index and a
- string representation of the value, and convert the result into a valid
- python identifier by replacing extraneous characters with ``_``.
-
- We avoid doing str(value) if dealing with non-trivial values.
- The problem is possible different names with different runs, e.g.
- different order of dictionary keys (see PYTHONHASHSEED) or dealing
- with mock objects.
- Trivial scalar values are passed as is.
-
- A "trivial" value is a plain scalar, or a tuple or list consisting
- only of trivial values.
- """
-
- # Add zeros before index to keep order
- index = "{0:0{1}}".format(index + 1, index_len)
- # 添加了对字典数据的处理
- if not is_trivial(value) and type(value) is not dict: #如果不符合value的要求,则直接返回用例名称_下标作为最终测试用例名字
- return "{0}_{1}".format(name, index)
- # 如果数据是字典,则获取字典当中的api_name对应的值,加到测试用例名称中
- if type(value) is dict:
- try:
- value = value["case_name"] #case_name作为value值
- except:
- return "{0}_{1}".format(name, index)
- try:
- value = str(value)
- except UnicodeEncodeError:
- # fallback for python2
- value = value.encode('ascii', 'backslashreplace')
- test_name = "{0}_{1}_{2}".format(name, index, value)
- return re.sub(r'\W|^(?=\d)', '_', test_name)
复制代码 ·数据处理文件
- import re
- from com.myconf import conf
- import random
- # 请求头
- class Header:
- headers = {'X-Lemonban-Media-Type': conf.get('Content-Type': conf.get('url_info','Content-Type'),'Authorization': None}
- class TestData:
- """专门用来保存一些替换的数据"""
- token = None
-
-
- def replace_data(data):
- # 判断是否有需要替换的数据
- while re.search("#(.+?)#", data): # .匹配任意字符,+重复一次或多次,?匹配0次或1次(变成非贪婪模式)()匹配分组:在匹配的数据中提取数据
- key = re.search("#(.+?)#", data).group(0) # 字典的键
- value = re.search("#(.+?)#", data).group(1) # 字典的值
- try:
- data = data.replace(key, conf.get('test_info', value)) # 替换信息为conf.ini中的值
- except:
- data = data.replace(key,getattr(TestData,value)) # 如果满足条件,且配置文件中没有配置数据,则读取临时变量的值
- return data
复制代码
|
|