51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 2588|回复: 2
打印 上一主题 下一主题

[转贴] Unittest框架写接口测试用例

[复制链接]
  • TA的每日心情
    无聊
    4 天前
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2020-10-12 14:00:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
     I.TestCase作用:是最小的测试单元,用于检查特定输入集合的特定返回值,可以用来创建新的测试用例
      II.编写测试用例规则
      (1)创建一个测试类,必须继承unnittest模块的TestCase类
      (2)创建一个测试方法,必须以"test"开头
      (3)调用被测试类,传入初始化数据
      (4)调用被测试方法,得到计算结果。用assertEqual()断言是否与预期结果相同。
      (5)调用unnitest的main()执行测试用例
    1.  .:一条运行通过的测试用例
    2.   F:一条运行失败的测试用例
    3.   E:一条运行错误的测试用例
    4.   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]结果
      完整代码:
    1. import os

    2.   import unittest

    3.   from library.ddt import ddt,data # ddt数据驱动

    4.   from com.doexcel import DoExcel # 操作excel数据

    5.   from com.contants import DATA_DIR # 测试用例模块所在目录

    6.   from com.myconf import conf #读取配置文件

    7.   from com.log import my_log # 日志处理对象

    8.   from com.handle_data import Header,replace_data,TestData # 数据处理

    9.   from com.handle_request import HandleRequest # http请求方法

    10.   from com.mysql import MySql # 导入数据库

    11.   excel_path = os.path.join(DATA_DIR,"testexcel.xlsx") # excel路径

    12.   @ddt

    13.   class TestClassName(unittest.TestCase):

    14.       excel = DoExcel(excel_path, "register")

    15.       cases = excel.read_data()  # 读取excel数据

    16.       http = HandleRequest() # 创建http请求对象

    17.       mysql = MySql()  # 创建数据库对象

    18.       @classmethod

    19.       def setUpClass(cls):

    20.           my_log.info("---------------开始执行TestClassName类测试用例---------")

    21.       def setUp(self):

    22.            pass

    23.           # 每条用例执行之前都会执行

    24.       @data(*cases)

    25.       def test_methodName(self,case):

    26.           # -----------------------第一步:准备用例数据-------------------------------------

    27.           # 用例方法参数

    28.           # 请求url

    29.           url = conf.get('url_info', 'url_base')+ case["url"]

    30.           # 请求方法

    31.           method = case["method"]

    32.           # 数据替换

    33.           case['data'] = replace_data(case['data'])

    34.           # excel中读的数据类型str转为json

    35.           data = eval(case["data"])

    36.           # 请求头

    37.           headers = getattr(Header, 'headers')

    38.           # 将token加到请求头中

    39.           headers['Authorization'] = getattr(TestData, 'token')

    40.           # 预期结果

    41.           expected = eval(case['expected'])

    42.           # 该用例在表单中所在行

    43.           row = int(case['case_id']) + 1

    44.           #-----------------------第二步:发送请求到接口,获取实际结果-------------------------------------

    45.           result = self.http.send(url = url,method = method,json = data,headers = headers).json()

    46.           TestResult = 'FAIL'  # 测试对比结果:默认为失败

    47.           try:

    48.               self.assertEqual(expected ['code'], result['code'])

    49.               TestResult = 'PASS'

    50.               my_log.info("执行用例:{0}--->执行通过".format(case["title"]))  # 将测试结果写入日志文件

    51.           except AssertionError as e:

    52.               my_log.info("执行用例:{0}--->未执行通过,出错位置为:{1}".format(case["title"], e))  # 将测试报错结果写入日志文件

    53.               raise e

    54.           finally:

    55.               self.excel.write_data(row = row, column = 9,value = str(result)) # 回写执行结果

    56.               self.excel.write_data(row = row,column = 9,value = TestResult) # 回写比对结果

    57.       def tearDown(self):

    58.           pass

    59.           # 每条用例执行之后都会执行

    60.       @classmethod

    61.       def tearDownClass(cls):

    62.           my_log.info("---------------结束执行TestClassName类测试用例---------")

    63.   if __name__ == '__main__':

    64.       unittest.main()
    复制代码

    说明:
      ·配置文件涉及内容:

    1. [url_info]

    2.   url_base = url

    3.   content-type = application/json; charset=UTF-8

    4.   [test_info]

    5.   ....
    复制代码
    ·ddt实现接口报告中按接口名显示用例(修改ddt中的mk_test_name())
    1.  def mk_test_name(name, value, index=0):

    2.       """

    3.       Generate a new name for a test case.

    4.   

    5.       It will take the original test name and append an ordinal index and a

    6.       string representation of the value, and convert the result into a valid

    7.       python identifier by replacing extraneous characters with ``_``.

    8.   

    9.       We avoid doing str(value) if dealing with non-trivial values.

    10.       The problem is possible different names with different runs, e.g.

    11.       different order of dictionary keys (see PYTHONHASHSEED) or dealing

    12.       with mock objects.

    13.       Trivial scalar values are passed as is.

    14.   

    15.       A "trivial" value is a plain scalar, or a tuple or list consisting

    16.       only of trivial values.

    17.       """

    18.      

    19.       # Add zeros before index to keep order

    20.       index = "{0:0{1}}".format(index + 1, index_len)

    21.       # 添加了对字典数据的处理

    22.       if not is_trivial(value) and type(value) is not dict: #如果不符合value的要求,则直接返回用例名称_下标作为最终测试用例名字

    23.           return "{0}_{1}".format(name, index)

    24.       #  如果数据是字典,则获取字典当中的api_name对应的值,加到测试用例名称中

    25.       if type(value) is dict:

    26.           try:

    27.               value = value["case_name"]   #case_name作为value值

    28.           except:

    29.               return "{0}_{1}".format(name, index)

    30.       try:

    31.           value = str(value)

    32.       except UnicodeEncodeError:

    33.           # fallback for python2

    34.           value = value.encode('ascii', 'backslashreplace')

    35.       test_name = "{0}_{1}_{2}".format(name, index, value)

    36.       return re.sub(r'\W|^(?=\d)', '_', test_name)
    复制代码
     ·数据处理文件
    1. import re

    2.   from com.myconf import conf

    3.   import random

    4.   # 请求头

    5.   class Header:

    6.       headers = {'X-Lemonban-Media-Type': conf.get('Content-Type': conf.get('url_info','Content-Type'),'Authorization': None}

    7.   class TestData:

    8.       """专门用来保存一些替换的数据"""  

    9.       token = None

    10.      

    11.   

    12.   def replace_data(data):

    13.      # 判断是否有需要替换的数据

    14.       while re.search("#(.+?)#", data):  # .匹配任意字符,+重复一次或多次,?匹配0次或1次(变成非贪婪模式)()匹配分组:在匹配的数据中提取数据

    15.           key = re.search("#(.+?)#", data).group(0) # 字典的键

    16.           value = re.search("#(.+?)#", data).group(1)  # 字典的值

    17.           try:

    18.               data = data.replace(key, conf.get('test_info', value))  # 替换信息为conf.ini中的值

    19.           except:

    20.               data = data.replace(key,getattr(TestData,value)) # 如果满足条件,且配置文件中没有配置数据,则读取临时变量的值

    21.       return data
    复制代码


    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏1
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-25 01:46 , Processed in 0.069255 second(s), 24 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表