0 1
TestCase作用
是最小的测试单元,用于检查特定输入集合的特定返回值,可以用来创建新的测试用例。
0 2
编写测试用例规则
(1)创建一个测试类,必须继承unnittest模块的TestCase类
(2)创建一个测试方法,必须以"test"开头
(3)调用被测试类,传入初始化数据
(4)调用被测试方法,得到计算结果。用assertEqual断言是否与预期结果相同。
(5)调用unnitest的main执行测试用例
.:一条运行通过的测试用例F:一条运行失败的测试用例E:一条运行错误的测试用例s:一条运行跳过的测试用例
0 3
定义测试方法
以test 开头的方法就是一条测试用例。
(1)准备用例数据:用例的参数(datas)和预期结果(excepted)
(2)执行功能函数,获取实际结果:result = res['code']
(3)对比实际结果和预期结果:(excepted, result)【用例执行通没通过的评判标准:断言异常】
0 4
测试用例包含内容
(1)数据处理
读取excel数据
数据驱动:ddt方法
替换excel数据:header加token,可变数据替换(正则替换)
excel数据格式处理:比如str转json-->eval,编号str转为int
(2)错误写入日志
(3)执行结果和对比结果写入excel
(4)查询数据库结果
完整代码
import osimport unittestfrom 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 = (DATA_DIR,"") # excel路径@ddtclass TestClassName():excel = DoExcel(excel_path, "sheetname")cases = excel.read_data # 读取excel数据http = HandleRequest # 创建http请求对象mysql = MySql # 创建数据库对象@classmethoddef setUpClass(cls):("---------------开始执行TestClassName类测试用例---------")def setUp(self):pass# 每条用例执行之前都会执行@data(*cases)def test_methodName(self,case):# -----------------------第一步:准备用例数据-------------------------------------# 用例方法参数# 请求urlurl = ('url_info', 'url_base')+ case["url"]# 请求方法method = case["method"]# 数据替换case['data'] = replace_data(case['data'])# excel中读的数据类型str转为jsondata = eval(case["data"])# 请求头headers = getattr(Header, 'headers')# 将token加到请求头中headers['Authorization'] = getattr(TestData, 'token')# 预期结果expected = eval(case['expected'])# 该用例在表单中所在行row = int(case['case_id']) + 1#-----------------------第二步:发送请求到接口,获取实际结果-------------------------------------result = (url = url,method = method,json = data,headers = headers).jsonTestResult = 'FAIL' # 测试对比结果:默认为失败try:(expected ['code'], result['code'])TestResult = 'PASS'("执行用例:{0}--->执行通过".format(case["title"])) # 将测试结果写入日志文件except Asserti as e:("执行用例:{0}--->未执行通过,出错位置为:{1}".format(case["title"], e)) # 将测试报错结果写入日志文件raise efinally:(row = row, column = 9,value = str(result)) # 回写执行结果(row = row,column = 9,value = TestResult) # 回写比对结果def tearDown(self):pass# 每条用例执行之后都会执行@classmethoddef tearDownClass(cls):("---------------结束执行TestClassName类测试用例---------")if __name__ == '__main__':
说明:
·配置文件涉及内容:
[url_info]url_base = urlcontent-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 astring representation of the value, and convert the result into a validpython 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 dealingwith mock objects.Trivial scalar values are passed as is.A "trivial" value is a plain scalar, or a tuple or list consistingonly of trivial values."""# Add zeros before index to keep orderindex = "{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 python2value = ('ascii', 'backslashreplace')test_name = "{0}_{1}_{2}".format(name, index, value)return re.sub(r'W|^(?=d)', '_', test_name)
·数据处理文件
import refrom com.myconf import confimport random# 请求头class Header:headers = {'X-Lemonban-Media-Type': ('Content-Type': ('url_info','Content-Type'),'Authorization': None}class TestData:"""专门用来保存一些替换的数据""" token = None
def replace_data(data): # 判断是否有需要替换的数据 while ("#(.+?)#", data): # .匹配任意字符,+重复一次或多次,?匹配0次或1次(变成非贪婪模式)匹配分组:在匹配的数据中提取数据 key = ("#(.+?)#", data).group(0) # 字典的键 value = ("#(.+?)#", data).group(1) # 字典的值 try: data = (key, ('test_info', value)) # 替换信息为中的值 except: data = (key,getattr(TestData,value)) # 如果满足条件,且配置文件中没有配置数据,则读取临时变量的值 return data