欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python+request+unittest實(shí)現(xiàn)接口測(cè)試框架集成實(shí)例

 更新時(shí)間:2018年03月16日 10:13:35   作者:Andrea-Pirlo  
這篇文章主要介紹了Python+request+unittest實(shí)現(xiàn)接口測(cè)試框架集成實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

1、為什么要寫代碼實(shí)現(xiàn)接口自動(dòng)化

大家知道很多接口測(cè)試工具可以實(shí)現(xiàn)對(duì)接口的測(cè)試,如postman、jmeter、fiddler等等,而且使用方便,那么為什么還要寫代碼實(shí)現(xiàn)接口自動(dòng)化呢?工具雖然方便,但也不足之處:

測(cè)試數(shù)據(jù)不可控制

接口測(cè)試本質(zhì)是對(duì)數(shù)據(jù)的測(cè)試,調(diào)用接口,輸入一些數(shù)據(jù),隨后,接口返回一些數(shù)據(jù)。驗(yàn)證接口返回?cái)?shù)據(jù)的正確性。在用工具運(yùn)行測(cè)試用例之前不得不手動(dòng)向數(shù)據(jù)庫(kù)中插入測(cè)試數(shù)據(jù)。這樣我們的接口測(cè)試是不是就沒有那么“自動(dòng)化了”。

無(wú)法測(cè)試加密接口

這是接口測(cè)試工具的一大硬傷,如我們前面開發(fā)的接口用工具測(cè)試完全沒有問(wèn)題,但遇到需要對(duì)接口參 數(shù)進(jìn)行加密/解密的接口,例如 md5、base64、AES 等常見加密方式。本書第十一章會(huì)對(duì)加密接口進(jìn)行介紹。 又或者接口的參數(shù)需要使用時(shí)間戳,也是工具很難模擬的。

擴(kuò)展能力不足

當(dāng)我們?cè)谙硎芄ぞ咚鶐?lái)的便利的同時(shí),往往也會(huì)受制于工具所帶來(lái)的局限。例如,我想將測(cè)試結(jié)果生 成 HMTL 格式測(cè)試報(bào)告,我想將測(cè)試報(bào)告發(fā)送到指定郵箱。我想對(duì)接口測(cè)試做定時(shí)任務(wù)。我想對(duì)接口測(cè)試做持續(xù)集成。這些需求都是工具難以實(shí)現(xiàn)的。

2、接口自動(dòng)化測(cè)試設(shè)計(jì)

接口測(cè)試調(diào)用過(guò)程可以用下圖概括,增加了測(cè)試數(shù)據(jù)庫(kù)

一般的 接口工具 測(cè)試過(guò)程:

1、接口工具調(diào)用被測(cè)系統(tǒng)的接口(傳參 username="zhangsan")。

2、系統(tǒng)接口根據(jù)傳參(username="zhangsan")向 正式數(shù)據(jù)庫(kù) 中查詢數(shù)據(jù)。

3、將查詢結(jié)果組裝成一定格式的數(shù)據(jù),并返回給被調(diào)用者。

4、人工或通過(guò)工具的斷言功能檢查接口測(cè)試的正確性。

接口自動(dòng)化測(cè)試項(xiàng)目,為了使接口測(cè)試對(duì)數(shù)據(jù)變得可控,測(cè)試過(guò)程如下:

1、接口測(cè)試項(xiàng)目先向 測(cè)試數(shù)據(jù)庫(kù) 中插入測(cè)試數(shù)據(jù)(zhangsan 的個(gè)人信息)。

2、調(diào)用被測(cè)系統(tǒng)接口(傳參 username="zhangsan")。

3、系統(tǒng)接口根據(jù)傳參(username="zhangsan")向測(cè)試數(shù)據(jù)庫(kù)中進(jìn)行查詢并得到 zhangsan 個(gè)人信息。

4、將查詢結(jié)果組裝成一定格式的數(shù)據(jù),并返回給被調(diào)用者。

5、通過(guò)單元測(cè)試框架斷言接口返回的數(shù)據(jù)(zhangsan 的個(gè)人信息),并生成測(cè)試報(bào)告。

為了使正式數(shù)據(jù)庫(kù)的數(shù)據(jù)不被污染,建議使用獨(dú)立的 測(cè)試數(shù)據(jù)庫(kù)

2、requests庫(kù)

Requests 使用的是 urllib3,因此繼承了它的所有特性。Requests 支持 HTTP 連接保持和連接池 ,支持 使用cookie保持會(huì)話 ,支持 文件上傳 ,支持 自動(dòng)確定響應(yīng)內(nèi)容的編碼。 對(duì)request庫(kù)的更詳細(xì)的介紹可以看我之前接口測(cè)試基礎(chǔ)的文章:

http://www.dbjr.com.cn/article/122571.htm?pc

http://www.dbjr.com.cn/article/108168.htm

3、接口測(cè)試代碼示例

下面以之前用 python+django 開發(fā)的用戶簽到系統(tǒng)為背景,展示接口測(cè)試的代碼。

為什么開發(fā)接口?開發(fā)的接口主要給誰(shuí)來(lái)用?

前端和后端分離是近年來(lái) Web 應(yīng)用開發(fā)的一個(gè)發(fā)展趨勢(shì)。這種模式將帶來(lái)以下優(yōu)勢(shì):

1、后端可以不用必須精通前端技術(shù)(HTML/JavaScript/CSS),只專注于數(shù)據(jù)的處理,對(duì)外提供 API 接口。

2、前端的專業(yè)性越來(lái)越高,通過(guò) API 接口獲取數(shù)據(jù),從而專注于頁(yè)面的設(shè)計(jì)。

3、前后端分離增加接口的應(yīng)用范圍,開發(fā)的接口可以應(yīng)用到 Web 頁(yè)面上,也可以應(yīng)用到移動(dòng) APP 上。

在這種開發(fā)模式下,接口測(cè)試工作就會(huì)變得尤為重要了。

開發(fā)實(shí)現(xiàn)的接口代碼示例:

# 添加發(fā)布會(huì)接口實(shí)現(xiàn)
def add_event(request):
  eid = request.POST.get('eid','')         # 發(fā)布會(huì)id
  name = request.POST.get('name','')        # 發(fā)布會(huì)標(biāo)題
  limit = request.POST.get('limit','')       # 限制人數(shù)
  status = request.POST.get('status','')      # 狀態(tài)
  address = request.POST.get('address','')     # 地址
  start_time = request.POST.get('start_time','')  # 發(fā)布會(huì)時(shí)間

  if eid =='' or name == '' or limit == '' or address == '' or start_time == '':
    return JsonResponse({'status':10021,'message':'parameter error'})

  result = Event.objects.filter(id=eid)
  if result:
    return JsonResponse({'status':10022,'message':'event id already exists'})

  result = Event.objects.filter(name=name)
  if result:
    return JsonResponse({'status':10023,'message':'event name already exists'})

  if status == '':
    status = 1

  try:
    Event.objects.create(id=eid,name=name,limit=limit,address=address,status=int(status),start_time=start_time)
  except ValidationError:
    error = 'start_time format error. It must be in YYYY-MM-DD HH:MM:SS format.'
    return JsonResponse({'status':10024,'message':error})

  return JsonResponse({'status':200,'message':'add event success'})

通過(guò)POST請(qǐng)求接收發(fā)布會(huì)參數(shù):發(fā)布會(huì)id、標(biāo)題、人數(shù)、狀態(tài)、地址和時(shí)間等參數(shù)。

首先,判斷eid、name、limit、address、start_time等字段均不能為空,否則JsonResponse()返回相應(yīng)的狀態(tài)碼和提示。JsonResponse()是一個(gè)非常有用的方法,它可以直接將字典轉(zhuǎn)化成Json格式返回到客戶端。

接下來(lái),判斷發(fā)布會(huì)id是否存在,以及發(fā)布會(huì)名稱(name)是否存在;如果存在將返回相應(yīng)的狀態(tài)碼和 提示信息。

再接下來(lái),判斷發(fā)布會(huì)狀態(tài)是否為空,如果為空,將狀態(tài)設(shè)置為1(True)。

最后,將數(shù)據(jù)插入到 Event 表,在插入的過(guò)程中如果日期格式錯(cuò)誤,將拋出 ValidationError 異常,接收 該異常并返回相應(yīng)的狀態(tài)和提示,否則,插入成功,返回狀態(tài)碼200和“add event success”的提示。

# 發(fā)布會(huì)查詢接口實(shí)現(xiàn)
def get_event_list(request):

  eid = request.GET.get("eid", "")   # 發(fā)布會(huì)id
  name = request.GET.get("name", "")  # 發(fā)布會(huì)名稱

  if eid == '' and name == '':
    return JsonResponse({'status':10021,'message':'parameter error'})

  if eid != '':
    event = {}
    try:
      result = Event.objects.get(id=eid)
    except ObjectDoesNotExist:
      return JsonResponse({'status':10022, 'message':'query result is empty'})
    else:
      event['eid'] = result.id
      event['name'] = result.name
      event['limit'] = result.limit
      event['status'] = result.status
      event['address'] = result.address
      event['start_time'] = result.start_time
      return JsonResponse({'status':200, 'message':'success', 'data':event})

  if name != '':
    datas = []
    results = Event.objects.filter(name__contains=name)
    if results:
      for r in results:
        event = {}
        event['eid'] = r.id
        event['name'] = r.name
        event['limit'] = r.limit
        event['status'] = r.status
        event['address'] = r.address
        event['start_time'] = r.start_time
        datas.append(event)
      return JsonResponse({'status':200, 'message':'success', 'data':datas})
    else:
      return JsonResponse({'status':10022, 'message':'query result is empty'})

通過(guò)GET請(qǐng)求接收發(fā)布會(huì)id和name 參數(shù)。兩個(gè)參數(shù)都是可選的。首先,判斷當(dāng)兩個(gè)參數(shù)同時(shí)為空,接口返回狀態(tài)碼10021,參數(shù)錯(cuò)誤。

如果發(fā)布會(huì)id不為空,優(yōu)先通過(guò)id查詢,因?yàn)閕d的唯一性,所以,查詢結(jié)果只會(huì)有一條,將查詢結(jié)果 以 key:value 對(duì)的方式存放到定義的event字典中,并將數(shù)據(jù)字典作為整個(gè)返回字典中data對(duì)應(yīng)的值返回。

name查詢?yōu)槟:樵?,查詢?shù)據(jù)可能會(huì)有多條,返回的數(shù)據(jù)稍顯復(fù)雜;首先將查詢的每一條數(shù)據(jù)放到一 個(gè)字典event中,再把每一個(gè)字典再放到數(shù)組datas中,最后再將整個(gè)數(shù)組做為返回字典中data對(duì)應(yīng)的值返回。

接口測(cè)試代碼示例

#查詢發(fā)布會(huì)接口測(cè)試代碼
import requests

url = "http://127.0.0.1:8000/api/get_event_list/"
r = requests.get(url, params={'eid':'1'})
result = r.json()
print(result)
assert result['status'] == 200
assert result['message'] == "success"
assert result['data']['name'] == "xx 產(chǎn)品發(fā)布會(huì)"
assert result['data']['address'] == "北京林匹克公園水立方"
assert result['data']['start_time'] == "2016-10-15T18:00:00"

因?yàn)椤鞍l(fā)布會(huì)查詢接口”是GET類型,所以,通過(guò)requests庫(kù)的get()方法調(diào)用,第一個(gè)參數(shù)為調(diào)用接口的URL地址,params設(shè)置接口的參數(shù),參數(shù)以字典形式組織。

json()方法可以將接口返回的json格式的數(shù)據(jù)轉(zhuǎn)化為字典。

接下來(lái)就是通過(guò) assert 語(yǔ)句對(duì)接字典中的數(shù)據(jù)進(jìn)行斷言。分別斷言status、message 和data的相關(guān)數(shù)據(jù)等。

使用unittest單元測(cè)試框架開發(fā)接口測(cè)試用例  

#發(fā)布會(huì)查詢接口測(cè)試代碼 
import unittest
import requests

class GetEventListTest(unittest.TestCase):

  def setUp(self):
    self.base_url = "http://127.0.0.1:8000/api/get_event_list/"

  def test_get_event_list_eid_null(self):
    ''' eid 參數(shù)為空 '''
    r = requests.get(self.base_url, params={'eid':''})
    result = r.json()
    self.assertEqual(result['status'], 10021)
    self.assertEqual(result['message'], 'parameter error')

  def test_get_event_list_eid_error(self):
    ''' eid=901 查詢結(jié)果為空 '''
    r = requests.get(self.base_url, params={'eid':901})
    result = r.json()
    self.assertEqual(result['status'], 10022)
    self.assertEqual(result['message'], 'query result is empty')

  def test_get_event_list_eid_success(self):
    ''' 根據(jù) eid 查詢結(jié)果成功 '''
    r = requests.get(self.base_url, params={'eid':1})
    result = r.json()
    self.assertEqual(result['status'], 200)
    self.assertEqual(result['message'], 'success')
    self.assertEqual(result['data']['name'],u'mx6發(fā)布會(huì)')
    self.assertEqual(result['data']['address'],u'北京國(guó)家會(huì)議中心')

  def test_get_event_list_nam_result_null(self):
    ''' 關(guān)鍵字‘a(chǎn)bc'查詢 '''
    r = requests.get(self.base_url, params={'name':'abc'})
    result = r.json()
    self.assertEqual(result['status'], 10022)
    self.assertEqual(result['message'], 'query result is empty')

  def test_get_event_list_name_find(self):
    ''' 關(guān)鍵字‘發(fā)布會(huì)'模糊查詢 '''
    r = requests.get(self.base_url, params={'name':'發(fā)布會(huì)'})
    result = r.json()
    self.assertEqual(result['status'], 200)
    self.assertEqual(result['message'], 'success')
    self.assertEqual(result['data'][0]['name'],u'mx6發(fā)布會(huì)')
    self.assertEqual(result['data'][0]['address'],u'北京國(guó)家會(huì)議中心')
49if __name__ == '__main__':
   unittest.main()

unittest單元測(cè)試框架可以幫助 組織和運(yùn)行接口測(cè)試用例。

4、接口自動(dòng)化測(cè)試框架實(shí)現(xiàn)

關(guān)于接口自動(dòng)化測(cè)試,unittest 已經(jīng)幫我們做了大部分工作,接下來(lái)只需要 集成數(shù)據(jù)庫(kù)操作 ,以及 HTMLTestRunner測(cè)試報(bào)告生成 擴(kuò)展即可。

框架結(jié)構(gòu)如下圖:

pyrequests 框架:

db_fixture/: 初始化接口測(cè)試數(shù)據(jù)。

interface/: 用于編寫接口自動(dòng)化測(cè)試用例。

report/: 生成接口自動(dòng)化測(cè)試報(bào)告。

db_config.ini : 數(shù)據(jù)庫(kù)配置文件。

HTMLTestRunner.py unittest 單元測(cè)試框架擴(kuò)展,生成 HTML 格式的測(cè)試報(bào)告。

run_tests.py : 執(zhí)行所有接口測(cè)試用例。

4.1、數(shù)據(jù)庫(kù)配置

首先,需要修改被測(cè)系統(tǒng)將數(shù)據(jù)庫(kù)指向測(cè)試數(shù)據(jù)庫(kù)。以 MySQL數(shù)據(jù)庫(kù)為例,針對(duì) django 項(xiàng)目而言,修改.../guest/settings.py 文件。可以在系統(tǒng)測(cè)試環(huán)境單獨(dú)創(chuàng)建一個(gè)測(cè)試庫(kù)。 這樣做的目的是讓接口測(cè)試的數(shù)據(jù)不會(huì)清空或污染到功能測(cè)試庫(kù)的數(shù)據(jù)。 其他框架開發(fā)的項(xiàng)目與django項(xiàng)目類似,這個(gè)工作一般由開發(fā)同學(xué)完成,我們測(cè)試同學(xué)更多關(guān)注的是測(cè)試框架的代碼。

4.2、框架代碼實(shí)現(xiàn)

4.2.1、首先,創(chuàng) 建數(shù)據(jù)庫(kù)配置文件.../db_config.ini

4.2.2、接下來(lái), 簡(jiǎn)單封裝數(shù)據(jù)庫(kù)操作,數(shù)據(jù)庫(kù)表數(shù)據(jù)的插入和清除 ,.../db_fixture/ mysql_db.py

import pymysql.cursors
import os
import configparser as cparser


# ======== Reading db_config.ini setting ===========
base_dir = str(os.path.dirname(os.path.dirname(__file__)))
base_dir = base_dir.replace('\\', '/')
file_path = base_dir + "/db_config.ini"

cf = cparser.ConfigParser()

cf.read(file_path)
host = cf.get("mysqlconf", "host")
port = cf.get("mysqlconf", "port")
db  = cf.get("mysqlconf", "db_name")
user = cf.get("mysqlconf", "user")
password = cf.get("mysqlconf", "password")


# ======== MySql base operating ===================
class DB:

  def __init__(self):
    try:
      # Connect to the database
      self.connection = pymysql.connect(host=host,
                       port=int(port),
                       user=user,
                       password=password,
                       db=db,
                       charset='utf8mb4',
                       cursorclass=pymysql.cursors.DictCursor)
    except pymysql.err.OperationalError as e:
      print("Mysql Error %d: %s" % (e.args[0], e.args[1]))

  # clear table data
  def clear(self, table_name):
    # real_sql = "truncate table " + table_name + ";"
    real_sql = "delete from " + table_name + ";"
    with self.connection.cursor() as cursor:
      cursor.execute("SET FOREIGN_KEY_CHECKS=0;")
      cursor.execute(real_sql)
    self.connection.commit()

  # insert sql statement
  def insert(self, table_name, table_data):
    for key in table_data:
      table_data[key] = "'"+str(table_data[key])+"'"
    key  = ','.join(table_data.keys())
    value = ','.join(table_data.values())
    real_sql = "INSERT INTO " + table_name + " (" + key + ") VALUES (" + value + ")"
    #print(real_sql)

    with self.connection.cursor() as cursor:
      cursor.execute(real_sql)

    self.connection.commit()

  # close database
  def close(self):
    self.connection.close()

  # init data
  def init_data(self, datas):
    for table, data in datas.items():
      self.clear(table)
      for d in data:
        self.insert(table, d)
    self.close()


if __name__ == '__main__':

  db = DB()
  table_name = "sign_event"
  data = {'id':1,'name':'紅米','`limit`':2000,'status':1,'address':'北京會(huì)展中心','start_time':'2016-08-20 00:25:42'}
  table_name2 = "sign_guest"
  data2 = {'realname':'alen','phone':12312341234,'email':'alen@mail.com','sign':0,'event_id':1}

  db.clear(table_name)
  db.insert(table_name, data)
  db.close()

首先,讀取 db_config.ini 配置文件。 創(chuàng)建 DB 類,__init__()方法初始化,通過(guò) pymysql.connect()連接數(shù)據(jù)庫(kù)。

因?yàn)檫@里只用到數(shù)據(jù)庫(kù)表的清除和插入,所以只創(chuàng)建 clear()和 insert()兩個(gè)方法。其中,insert()方法對(duì)數(shù) 據(jù)的插入做了簡(jiǎn)單的格式轉(zhuǎn)化,可將字典轉(zhuǎn)化成 SQL 插入語(yǔ)句,這樣格式轉(zhuǎn)化了方便了數(shù)據(jù)庫(kù)表數(shù)據(jù)的創(chuàng)建。

最后,通過(guò) close()方法用于關(guān)閉數(shù)據(jù)庫(kù)連接。

4.2.3、接下來(lái)接下來(lái) 創(chuàng)建測(cè)試數(shù)據(jù) ,.../db_fixture/ test_data.py

import sys
sys.path.append('../db_fixture')
try:
  from mysql_db import DB
except ImportError:
  from .mysql_db import DB

# create data
datas = {
  'sign_event':[
    {'id':1,'name':'紅米Pro發(fā)布會(huì)','`limit`':2000,'status':1,'address':'北京會(huì)展中心','start_time':'2017-08-20 14:00:00'},
    {'id':2,'name':'可參加人數(shù)為0','`limit`':0,'status':1,'address':'北京會(huì)展中心','start_time':'2017-08-20 14:00:00'},
    {'id':3,'name':'當(dāng)前狀態(tài)為0關(guān)閉','`limit`':2000,'status':0,'address':'北京會(huì)展中心','start_time':'2017-08-20 14:00:00'},
    {'id':4,'name':'發(fā)布會(huì)已結(jié)束','`limit`':2000,'status':1,'address':'北京會(huì)展中心','start_time':'2001-08-20 14:00:00'},
    {'id':5,'name':'小米5發(fā)布會(huì)','`limit`':2000,'status':1,'address':'北京國(guó)家會(huì)議中心','start_time':'2017-08-20 14:00:00'},
  ],
  'sign_guest':[
    {'id':1,'realname':'alen','phone':13511001100,'email':'alen@mail.com','sign':0,'event_id':1},
    {'id':2,'realname':'has sign','phone':13511001101,'email':'sign@mail.com','sign':1,'event_id':1},
    {'id':3,'realname':'tom','phone':13511001102,'email':'tom@mail.com','sign':0,'event_id':5},
  ],
}

# Inster table datas
def init_data():
  DB().init_data(datas)


if __name__ == '__main__':
  init_data()

init_data()函數(shù)用于讀取 datas 字典中的數(shù)據(jù),調(diào)用 DB 類中的 clear()方法清除數(shù)據(jù)庫(kù),然后,調(diào)用 insert() 方法插入表數(shù)據(jù)。

4.2.4、編寫 接口測(cè)試用例 。創(chuàng)建添加發(fā)布會(huì)接口測(cè)試文件.../interface/ add_event_test.py

import unittest
import requests
import os, sys
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, parentdir)
from db_fixture import test_data


class AddEventTest(unittest.TestCase):
  ''' 添加發(fā)布會(huì) '''

  def setUp(self):
    self.base_url = "http://127.0.0.1:8000/api/add_event/"

  def tearDown(self):
    print(self.result)

  def test_add_event_all_null(self):
    ''' 所有參數(shù)為空 '''
    payload = {'eid':'','':'','limit':'','address':"",'start_time':''}
    r = requests.post(self.base_url, data=payload)
    self.result = r.json()
    self.assertEqual(self.result['status'], 10021)
    self.assertEqual(self.result['message'], 'parameter error')

  def test_add_event_eid_exist(self):
    ''' id已經(jīng)存在 '''
    payload = {'eid':1,'name':'一加4發(fā)布會(huì)','limit':2000,'address':"深圳寶體",'start_time':'2017'}
    r = requests.post(self.base_url, data=payload)
    self.result = r.json()
    self.assertEqual(self.result['status'], 10022)
    self.assertEqual(self.result['message'], 'event id already exists')

  def test_add_event_name_exist(self):
    ''' 名稱已經(jīng)存在 '''
    payload = {'eid':11,'name':'紅米Pro發(fā)布會(huì)','limit':2000,'address':"深圳寶體",'start_time':'2017'}
    r = requests.post(self.base_url,data=payload)
    self.result = r.json()
    self.assertEqual(self.result['status'], 10023)
    self.assertEqual(self.result['message'], 'event name already exists')

  def test_add_event_data_type_error(self):
    ''' 日期格式錯(cuò)誤 '''
    payload = {'eid':11,'name':'一加4手機(jī)發(fā)布會(huì)','limit':2000,'address':"深圳寶體",'start_time':'2017'}
    r = requests.post(self.base_url,data=payload)
    self.result = r.json()
    self.assertEqual(self.result['status'], 10024)
    self.assertIn('start_time format error.', self.result['message'])

  def test_add_event_success(self):
    ''' 添加成功 '''
    payload = {'eid':11,'name':'一加4手機(jī)發(fā)布會(huì)','limit':2000,'address':"深圳寶體",'start_time':'2017-05-10 12:00:00'}
    r = requests.post(self.base_url,data=payload)
    self.result = r.json()
    self.assertEqual(self.result['status'], 200)
    self.assertEqual(self.result['message'], 'add event success')


if __name__ == '__main__':
  test_data.init_data() # 初始化接口測(cè)試數(shù)據(jù)
  unittest.main()

在測(cè)試接口之前,調(diào)用test_data.py文件中的init_data()方法初始化數(shù)據(jù)庫(kù)中的測(cè)試數(shù)據(jù)。

創(chuàng)建AddEventTest測(cè)試類繼承 unittest.TestCase 類,通過(guò)創(chuàng)建測(cè)試用例,調(diào)用相關(guān)接口,并驗(yàn)證接口返回 的數(shù)據(jù)。

4.2.5、創(chuàng)建 run_tests.py 文件

當(dāng)開發(fā)的接口達(dá)到一定數(shù)量后,就需要考慮 分文件分目錄 的來(lái) 劃分 接口測(cè)試用例,如何批量的執(zhí)行不同文件目錄下的用例呢?unittest單元測(cè)試框架提供的 discover() 方法可以幫助我們做到這一點(diǎn)。并使用 HTMLTestRunner 擴(kuò)展生成 HTML 格式的測(cè)試報(bào)告。

import time, sys
sys.path.append('./interface')
sys.path.append('./db_fixture')
from HTMLTestRunner import HTMLTestRunner
import unittest
from db_fixture import test_data


# 指定測(cè)試用例為當(dāng)前文件夾下的 interface 目錄
test_dir = './interface'
discover = unittest.defaultTestLoader.discover(test_dir, pattern='*_test.py')


if __name__ == "__main__":
  test_data.init_data() # 初始化接口測(cè)試數(shù)據(jù)

  now = time.strftime("%Y-%m-%d %H_%M_%S")
  filename = './report/' + now + '_result.html'
  fp = open(filename, 'wb')
  runner = HTMLTestRunner(stream=fp,
              title='Guest Manage System Interface Test Report',
              description='Implementation Example with: ')
  runner.run(discover)
  fp.close()

首先,通過(guò)調(diào)用test_data.py文件中的init_data()函數(shù)來(lái)初始化接口測(cè)試數(shù)據(jù)。

使用unittest框架所提供的discover()方法,查找 interface/ 目錄下,所有匹配*_test.py 的測(cè)試文件(*星 號(hào)匹配任意字符)。

HTMLTestRunner 為unittest單元測(cè)試框架的擴(kuò)展,利用它所提供的HTMLTestRunner()類來(lái)替換unittest單元測(cè)試框架的TextTestRunner()類,從而生成HTML格式的測(cè)試報(bào)告。

遺憾的是HTMLTestRunner并不支持Python3.x,大家可以在網(wǎng)上找到適用于Python3.x的HTMLTestRunner.py文件,使用在自己的接口自動(dòng)化工程中。

通過(guò) time 的 strftime()方法獲取當(dāng)前時(shí)間,并且轉(zhuǎn)化成一定的時(shí)間格式。作為測(cè)試報(bào)告的名稱。這樣做目的是是為了避免因?yàn)樯傻膱?bào)告的名稱重名而造成報(bào)告的覆蓋。最終,將測(cè)試報(bào)告存放于report/目錄下面。如下圖,一張完整的接口自動(dòng)化測(cè)試報(bào)告。

 

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python實(shí)現(xiàn)將HTML轉(zhuǎn)為PDF/圖片/XML/XPS格式

    Python實(shí)現(xiàn)將HTML轉(zhuǎn)為PDF/圖片/XML/XPS格式

    網(wǎng)頁(yè)內(nèi)容是信息傳播的主要形式之一,這篇文章主要和大家介紹了如何使用Python實(shí)現(xiàn)將HTML分別轉(zhuǎn)為PDF/圖片/XML/XPS格式等,需要的可以參考下
    2024-03-03
  • python獲取list下標(biāo)及其值的簡(jiǎn)單方法

    python獲取list下標(biāo)及其值的簡(jiǎn)單方法

    下面小編就為大家?guī)?lái)一篇python獲取list下標(biāo)及其值的簡(jiǎn)單方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-09-09
  • Python實(shí)現(xiàn)動(dòng)態(tài)圖解析、合成與倒放

    Python實(shí)現(xiàn)動(dòng)態(tài)圖解析、合成與倒放

    這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)動(dòng)態(tài)圖的解析、合成與倒放,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Python數(shù)據(jù)結(jié)構(gòu)之單鏈表詳解

    Python數(shù)據(jù)結(jié)構(gòu)之單鏈表詳解

    這篇文章主要為大家詳細(xì)介紹了Python數(shù)據(jù)結(jié)構(gòu)之單鏈表的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • 解決新django中的path不能使用正則表達(dá)式的問(wèn)題

    解決新django中的path不能使用正則表達(dá)式的問(wèn)題

    今天小編就為大家分享一篇解決新django中的path不能使用正則表達(dá)式的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • Python中print函數(shù)語(yǔ)法格式以及各參數(shù)舉例詳解

    Python中print函數(shù)語(yǔ)法格式以及各參數(shù)舉例詳解

    這篇文章主要給大家介紹了關(guān)于Python中print函數(shù)語(yǔ)法格式以及各參數(shù)舉例詳解的相關(guān)資料,print()函數(shù)用于將指定的字符串或?qū)ο?通常是字符串)輸出到屏幕或文件中,需要的朋友可以參考下
    2023-10-10
  • 用Python編寫個(gè)解釋器實(shí)現(xiàn)方法接受

    用Python編寫個(gè)解釋器實(shí)現(xiàn)方法接受

    計(jì)算機(jī)只能理解機(jī)器碼。歸根結(jié)底,編程語(yǔ)言只是一串文字,目的是為了讓人類更容易編寫他們想讓計(jì)算機(jī)做的事情。真正的魔法是由編譯器和解釋器完成,它們彌合了兩者之間的差距。解釋器逐行讀取代碼并將其轉(zhuǎn)換為機(jī)器碼
    2023-01-01
  • 詳解Python 4.0 預(yù)計(jì)推出的新功能

    詳解Python 4.0 預(yù)計(jì)推出的新功能

    這篇文章主要介紹了詳解Python 4.0 預(yù)計(jì)推出的新功能,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-07-07
  • pandas實(shí)現(xiàn)一行拆分成多行

    pandas實(shí)現(xiàn)一行拆分成多行

    這篇文章主要介紹了pandas實(shí)現(xiàn)一行拆分成多行方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • Python 合并多個(gè)TXT文件并統(tǒng)計(jì)詞頻的實(shí)現(xiàn)

    Python 合并多個(gè)TXT文件并統(tǒng)計(jì)詞頻的實(shí)現(xiàn)

    這篇文章主要介紹了Python 合并多個(gè)TXT文件并統(tǒng)計(jì)詞頻的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08

最新評(píng)論