zoukankan      html  css  js  c++  java
  • unittest框架写接口测试用例(TestCase)

    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)【用例执行通没通过的评判标准:断言异常】

    方法检查版本
    assertEqual(a, b) a == b是否相等  
    assertNotEqual(a, b) a != b  
    assertTrue(x) bool(x)is True布尔值判断  
    assertFalse(x) bool(x)is False  
    assertIs(a, b) a is b 身份判断:是否同一个对象判断 3.1
    assertIsNot(a, b) a is not b 3.1
    assertIsNone(x) x is None 3.1
    assertIsNotNone(x) x is not None 3.1
    assertIn(a, b) a in b 成员判断 3.1
    assertNotIn(a, b) a not in b 3.1
    assertIsInstance(a, b) isinstance(a, b) 3.2
    assertNotIsInstance(a, b) not isinstance(a, b) 3.2

    IV.测试用例包含内容

    (1)数据处理

    • 读取excel数据
    • 数据驱动:ddt方法
    • 替换excel数据:header加token,可变数据替换(正则替换)
    • excel数据格式处理:比如str转json-->eval,编号str转为int

    (2)错误写入日志

    (3)执行结果和对比结果写入excel

    (4)查询数据库结果

    完整代码

    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, "sheetname")
        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
  • 相关阅读:
    iOS 9 新特性 UIStackView
    自定义 URL Scheme 完全指南
    使用NSURLCache缓存
    swift 3.0 新特征
    《转之微信移动团队微信公众号》iOS 事件处理机制与图像渲染过程
    《转》使用NSURLSession发送GET和POST请求
    《转》IOS 扩展 (Extension)
    《转》__block修饰符
    《转》Objective-C Runtime(4)- 成员变量与属性
    《转》Objective-C Runtime(3)- 消息 和 Category
  • 原文地址:https://www.cnblogs.com/kite123/p/13786730.html
Copyright © 2011-2022 走看看