python接口自动化-实战(第二阶段)

再次强调,因为视频中实战地址已无法访问,建议大家根据原理,用自己公司的业务逻辑、代码来练手。本人公司使用pyhon2.7,所以语法可能与3.x不同

目标

  • 复习单元测试:引入单元测试、html测试报告、断言结果
  • 引入超继承(二选一)
  • 引入ddt(二选一)
  • 添加一个字段存入测试结果
  • 引入try...except...finally
  • 完成用例的可配置化,想跑哪条用例,通过配置文件配置好
  • 难点:
    • 同时跑多个模块怎么跑

复习单元测试

使用unittest,测试我们自己封装的http请求类-HttpRequest,目的一:学习如何进行单元测试,目的二:写出咱们的各个接口。

  • 新建test_http_request.py编写测试用例

    import json
    import unittest
    from common.public.http_request import HttpRequest
    
    class TestHttpRequest(unittest.TestCase):
    
        def setUp(self):
            pass
    
        def tearDown(self):
            pass
        
        #登录接口
        def test_login(self): 
            payload = {"user_phone": "1801923****", "device_model": "iphone7"}
            res=HttpRequest().http_request("1.6.0", "android", "785c6fee0e4488ca412a5afc9a00e9d8","/login","post",payload)
            self.assertEqual(200,res.status_code)  #添加断言
            print ("获得的结果是:",res.json()) 
    
  • run.py文件中加载用例、执行用例

    import unittest
    from common.public.test_http_request import TestHttpRequest
    
    suite=unittest.TestSuite()
    suite.addTest(TestHttpRequest("test_login")) #添加用例
    
    #执行用例
    runner=unittest.TextTestRunner()
    runner.run(suite)
    
  • 使用HTMLTestRunner生成HTML测试报告

    下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html

    使用:

      - HTMLTestRunner是Python标准库的unittest模块的扩展,无法通过pip安装
      - 下载HTMLTestRunner.py放在lib目录下
      - 导入模块 `import HTMLTestRunner`
    

    注意点:

    • 使用python2.x可以直接使用,python3.x需要进行改造。

    • 在文章python基础之类与对象的应用-单元测试unittest模块 中讲过了。

    代码改造为使用HTMLTestRunner生成HTML测试报告:

    # encoding:utf-8
    
    import sys
    reload(sys)
    sys.setdefaultencoding('utf8') #python2.7需要添加,否则会因编码问题报错
    
    import HTMLTestRunner
    import unittest
    from common.public.test_http_request import TestHttpRequest
    
    suite=unittest.TestSuite()
    suite.addTest(TestHttpRequest("test_login")) #添加用例
    
    with open("test_result/rusult.html","wb") as file:
        #执行用例
        runner=HTMLTestRunner.HTMLTestRunner(stream=file,verbosity=2,title="测试HttpRequest类")
        runner.run(suite)
    

    获得的html格式的测试报告:

    python接口自动化-实战(第二阶段)_第1张图片
    image

引入ddt

引入ddt的目的是为了数据分离、数据驱动测试。所谓数据驱动,从它的定义来看,就是数据的改变从而驱动自动化测试的执行,最终引起测试结果的改变。说的直白些,就是参数化的应用。值得注意的是,ddt适用于测试数据是列表嵌套列表或者列表嵌套字典。

  • 给测试数据中新增一列expected,用于添加断言的预期结果


    image
  • 修改do_excel.py,读取expected的数据:

    get_data()方法中新增:sub_data["expected"] = sheet.cell(i, 6).value
    write_back_data()方法中修改:sheet.cell(i,7).value=value

  • 改造测试用例test_http_request.py

    import unittest
    from common.public.http_request import HttpRequest
    from ddt import ddt,data
    from common.public.do_excel import DoExcel
    
    test_data=DoExcel().get_data("../../test_data/test_data.xlsx","Sheet1")
    
    @ddt
    class TestHttpRequest(unittest.TestCase):
    
        def setUp(self):
            pass
    
        def tearDown(self):
            pass
        @data(*test_data)
        def test_login(self,item): #添加item,即测试数据
            res=HttpRequest().http_request(item["url"],item["method"],eval(item["payload"]))
            self.assertEqual(str(item["expected"]),str(res.status_code))
            print "获得的结果是:",res.json()
    
  • 改造run.py

    import HTMLTestRunner
    import unittest
    from common.public.test_http_request import TestHttpRequest
    
    suite=unittest.TestSuite()
    loader=unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestHttpRequest))
    
    with open("test_result/rusult.html","wb") as file:
        #执行用例
        runner=HTMLTestRunner.HTMLTestRunner(stream=file,verbosity=2,title="测试HttpRequest类")
        runner.run(suite)
    
    • 问题:因为test_http_request.pyrun.py不是一个层级,所以这样运行run.py会报错,找不到test_data.xlsx,所以在test_http_request.py中的test_data地址改为绝对路径。but,如果设置为绝对路径,那么在自己电脑上能跑,在别人电脑上可能会失败。

    • 解决方案:路径可配置

      • os.path.split()函数,将文件名和路径分割开
      • os.path.split(path)[0],取上级目录
      • os.path.join(path,*paths),拼接路径不用加/
      import os
      """专门读取路径的值"""
      
      #获取当前文件所在绝对路径,包括模块名,__file__表示是当前文件本身
      path=os.path.realpath(__file__)
      
      #获取顶级目录的绝对路径
      project_path=os.path.split(os.path.split(os.path.split(path)[0])[0])[0]
      
      #获取测试数据的绝对路径
      test_data_path=os.path.join(project_path,"test_data","test_data.xlsx")
      
      #获取测试报告的绝对路径
      test_result_path=os.path.join(project_path,"test_result","html_report","result.html")
      
      • 使用project_path.py中的路径
        • 引入project_path.pyfrom common.public.project_path import *
        • test_http_request.py中:test_data=DoExcel().get_data(test_data_path,"Sheet1")
        • run.py中:with open(test_result_path,"wb") as file:

添加字段存入测试结果

1.result字段存放response.json()

添加:DoExcel().write_back_data(test_data_path,"Sheet1",item["case_id"]+1,str(res.json))

# encoding: utf-8
import json
import unittest
from common.public.http_request import HttpRequest
from ddt import ddt,data
from common.public.do_excel import DoExcel
from common.public.project_path import *

test_data=DoExcel().get_data(test_data_path,"Sheet1")

@ddt
class TestHttpRequest(unittest.TestCase):

    def setUp(self):
        pass

    def tearDown(self):
        pass
    @data(*test_data)
    def test_login(self,item):
        res=HttpRequest().http_request(item["url"],item["method"],eval(item["payload"]))
        self.assertEqual(str(item["expected"]),str(res.status_code))  
        #将res.json写入excel中
        DoExcel().write_back_data(test_data_path,"Sheet1",item["case_id"]+1,str(res.json)) 
        print "获得的结果是:", res.json()

  • 问题:一,报错时,因为执行不到print语句,从result.html中无法看出时什么问题。二,如果报错时,res.json()就无法写入到excel文件中。
  • 解决:使用finally,是无论有没有捕获到异常都执行finally下的代码(代码在后面展示)

2.新增一个TestResult字段存放测试结果

与result字段不同,result字段存放的是response.json(),TestResult字段存入Pass/Failed,表示用例成功还是失败。写入excel后可以直接通过excel筛选,只查看为Failed的用例

  • 首先在test_data.xlsx中添加字段TestResult

    image
  • 改造测试用例test_http_request.py

    test_data=DoExcel().get_data(test_data_path,"Sheet1")
    
    @ddt
    class TestHttpRequest(unittest.TestCase):
    
        def setUp(self):
            pass
    
        def tearDown(self):
            pass
            
        @data(*test_data)
        def test_login(self,item):
            res=HttpRequest().http_request(item["url"],item["method"],eval(item["payload"]))
            #捕获异常
            try:
                self.assertEqual(str(item["expected"]),str(res.status_code)) 
                #如果没有异常, TestResult="Pass"
                TestResult="Pass"
            except AssertionError as e:
                #如果有异常, TestResult="Failed"
                TestResult = "Failed"
                print "测试用例失败,{0}".format(e)
                raise e
            #无论是否捕获异常都执行
            finally:
                print "获得的结果是:", res.json()
                DoExcel().write_back_data(test_data_path,"Sheet1",item["case_id"]+1,str(res.json())
    
  • 改造do_excel.py写入TestResult字段

    def write_back_data(self,file_name,sheet_name,i,result,TestResult):
        wb=load_workbook(file_name)
        sheet=wb[sheet_name]
        sheet.cell(i,7).value=result
        sheet.cell(i,8).value=TestResult
        wb.save(file_name) #保存
    

    同时,test_http_request.py中添加TestResult字段:
    DoExcel().write_back_data(test_data_path,"Sheet1",item["case_id"]+1,str(res.json(),TestResult)

用例可配置

实现多个用例同时执行、多个模块同时执行

配置文件效果:

[MODE]
mode={"login":"all",
      "register":[1,2,4,5],
      "recharge":[1,2]
      }

通过option和value,配置不同的用例,option是对应的模块(使用不同的sheet放置不同的模块,对应sheetname),value的all代表该模块所有用例,列表里的数字代表case_id,

  • 新建一个配置文件case.conf
  • 写一个读取配置文件的类
import configparser

class ReadConfig:

    @staticmethod
    def get_config(file_path,setion,option):
        cf=configparser.ConfigParser()
        cf.read(file_path)
        return cf[setion][option]
        
if __name__ == '__main__': #测试
    from common.public import project_path
    print ReadConfig.get_config(project_path.case_config_path,"MODE","mode")

控制台输出:

python接口自动化-实战(第二阶段)_第2张图片
image
  • 改造do_excel.py

    class DoExcel:
    
        @staticmethod  #静态方法,直接调用
        def get_data(file_name):
            wb=load_workbook(file_name)
            mode=eval(ReadConfig.get_config(project_path.case_config_path,"MODE","mode"))
    
            test_data=[]
            #循环配置文件中的mode的key
            for key in mode:
                sheet=wb[key] 
                #如果为all,跑所有的case
                if mode[key]=='all':
                    for i in range(2,sheet.max_row+1):
                        row_data={}
                        row_data["case_id"] = sheet.cell(i, 1).value
                        row_data["url"]=sheet.cell(i,2).value
                        row_data["method"]=sheet.cell(i,3).value
                        row_data["payload"]=sheet.cell(i,4).value
                        row_data["title"]=sheet.cell(i,5).value
                        row_data["expected"] = sheet.cell(i, 6).value
                        #读取sheet_name
                        row_data["sheet_name"]=key
                        test_data.append(row_data)
                else:
                #如果不是all,按case_id跑
                    for case_id in mode[key]:
                        row_data = {}
                        row_data["case_id"] = sheet.cell(case_id+1, 1).value
                        row_data["url"] = sheet.cell(case_id+1, 2).value
                        row_data["method"] = sheet.cell(case_id+1, 3).value
                        row_data["payload"] = sheet.cell(case_id+1, 4).value
                        row_data["title"] = sheet.cell(case_id+1, 5).value
                        row_data["expected"] = sheet.cell(case_id+1, 6).value
                        row_data["sheet_name"] = key 
                        test_data.append(row_data)
    
            return test_data
    
        @staticmethod
        def write_back_data(file_name,sheet_name,i,result,TestResult):
            wb=load_workbook(file_name)
            sheet=wb[sheet_name]
            sheet.cell(i,7).value=result
            sheet.cell(i,8).value=TestResult
            wb.save(file_name) #保存
    
    
  • 改造测试用例test_http_request.py

    修改sheet_name参数化:

    DoExcel().write_back_data(test_data_path,item["sheet_name"],item["case_id"]+1,str(res.json()),TestResult)
    

你可能感兴趣的:(python接口自动化-实战(第二阶段))