美文网首页
python接口自动化-实战(第二阶段)

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

作者: DayBreakL | 来源:发表于2019-10-11 16:43 被阅读0次

    再次强调,因为视频中实战地址已无法访问,建议大家根据原理,用自己公司的业务逻辑、代码来练手。本人公司使用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`
      

      注意点:

      代码改造为使用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格式的测试报告:

      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")
    

    控制台输出:

    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接口自动化-实战(第二阶段)

          本文链接:https://www.haomeiwen.com/subject/wyhxmctx.html