1. 程式人生 > >Python接口測試實戰4(上) - 接口測試框架實戰

Python接口測試實戰4(上) - 接口測試框架實戰

wal 讀取方法 使用方法 pre 配套 cursor 需要 code gem

如有任何學習問題,可以添加作者微信:lockingfree

課程目錄

Python接口測試實戰1(上)- 接口測試理論
Python接口測試實戰1(下)- 接口測試工具的使用
Python接口測試實戰2 - 使用Python發送請求
Python接口測試實戰3(上)- Python操作數據庫
Python接口測試實戰3(下)- unittest測試框架
Python接口測試實戰4(上) - 接口測試框架實戰
Python接口測試實戰4(下) - 框架完善:用例基類,用例標簽,重新運行上次失敗用例
Python接口測試實戰5(上) - Git及Jenkins持續集成
Python接口測試實戰5(下) - RESTful、Web Service及Mock Server

更多學習資料請加QQ群: 822601020獲取

本節內容

  • 數據分離 - 從Excel中讀取數據
  • 增加log功能
  • 發送郵件
  • 使用配置文件
  • 框架整理

技術分享圖片

數據分離 - 從Excel中讀取數據

之前的用例中,數據直接寫在代碼文件裏,不利於修改和構造數據
這裏我們使用Excel保存測試數據,實現代碼和數據的分離
新建Excel文件test_user_data.xlsx包含兩個工作簿TestUserLoginTestUserReg,並復制到項目根目錄下
技術分享圖片

TestUserLogin
|case_name|url|method|data|expect_res|
|---|---|---|---|---|
test_user_login_normal|http://115.28.108.130:5000/api/user/login/|POST| {"name": "張三","password":"123456"}|<h1>登錄成功</h1>


test_user_login_password_wrong |http://115.28.108.130:5000/api/user/login/|POST|{"name": "張三","password":"1234567"}|<h1>失敗,用戶名或密碼錯誤</h1>

TestUserReg
case_name|url|method|data|expect_res
|---|---|---|---|---|
test_user_reg_normal|http://115.28.108.130:5000/api/user/login/|POST| {"name": "範冰冰","password":"123456"}|"{"code: "100000","msg": "成功,"data": {""name": "範冰冰,"password": "e10adc3949ba59abbe56e057f20f883e"}}"
test_user_reg_exist|http://115.28.108.130:5000/api/user/login/|POST| {"name": "張三","password":"123456"}|"{"code": "100001","msg": "失敗,用戶已存在","data": {"name": "張三","password":"e10adc3949ba59abbe56e057f20f883e"}}"

Excel讀取方法:
Python我們使用三方庫xlrd來讀取Excel

安裝方法: pip install xlrd

import xlrd

wb = xlrd.open_workbook("test_user_data.xlsx")  # 打開excel
sh = wb.sheet_by_name("TestUserLogin")  # 按工作簿名定位工作表
print(sh.nrows)  # 有效數據行數
print(sh.ncols)  # 有效數據列數
print(sh.cell(0, 0).value)  # 輸出第一行第一列的值`case_name`
print(sh.row_values(0))  # 輸出第1行的所有值(列表格式)

# 將數據和標題組裝成字典,使數據更清晰
print(dict(zip(sh.row_values(0), sh.row_values(1))))

# 遍歷excel,打印所有的數據
for i in range(sh.nrows):
    print(sh.row_values(i))

結果:

3
5
case_name
[‘case_name‘, ‘url‘, ‘method‘, ‘data‘, ‘expect_res‘]
{‘case_name‘: ‘test_user_login_normal‘, ‘url‘: ‘http://115.28.108.130:5000/api/user/login/‘, ‘method‘: ‘POST‘, ‘data‘: ‘{"name": "張三","password":"123456"}‘, ‘expect_res‘: ‘<h1>登錄成功</h1>‘}
[‘case_name‘, ‘url‘, ‘method‘, ‘data‘, ‘expect_res‘]
[‘test_user_login_normal‘, ‘http://115.28.108.130:5000/api/user/login/‘, ‘POST‘, ‘{"name": "張三","password":"123456"}‘, ‘<h1>登錄成功</h1>‘]
[‘test_user_login_password_wrong‘, ‘http://115.28.108.130:5000/api/user/login/‘, ‘POST‘, ‘{"name": "張三","password":"1234567"}‘, ‘<h1>失敗,用戶不存在</h1>‘]

封裝讀取excel操作:
新建read_excel.py
技術分享圖片

我們的目的是獲取某條用例的數據,需要3個參數,excel數據文件名(data_file),工作簿名(sheet),用例名(case_name)
如果我們只封裝一個函數,每次調用(每條用例)都要打開一次excel並遍歷一次,這樣效率比較低。
我們可以拆分成兩個函數,一個函數excel_to_list(data_file, sheet),一次獲取一個工作表的所有數據,另一個函數get_test_data(data_list, case_name)從所有數據中去查找到該條用例的數據。

import xlrd

def excel_to_list(data_file, sheet):
    data_list = []  # 新建個空列表,來乘裝所有的數據
    wb = xlrd.open_workbook(data_file)  # 打開excel
    sh = wb.sheet_by_name(sheet)  # 獲取工作簿
    header = sh.row_values(0)  # 獲取標題行數據
    for i in range(1, sh.nrows):  # 跳過標題行,從第二行開始取數據
        d = dict(zip(header, sh.row_values(i)))  # 將標題和每行數據組裝成字典
        data_list.append(d)
    return data_list  # 列表嵌套字典格式,每個元素是一個字典

def get_test_data(data_list, case_name):
    for case_data in data_list:
        if case_name == case_data[‘case_name‘]:  # 如果字典數據中case_name與參數一致
            return case_data
            # 如果查詢不到會返回None

if __name__ == ‘__main__‘:   # 測試一下自己的代碼
    data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin")  # 讀取excel,TestUserLogin工作簿的所有數據
    case_data = get_test_data(data_list, ‘test_user_login_normal‘)  # 查找用例‘test_user_login_normal‘的數據
    print(case_data)

輸出結果:

{‘case_name‘: ‘test_user_login_normal‘, ‘url‘: ‘http://115.28.108.130:5000/api/user/login/‘, ‘method‘: ‘POST‘, ‘data‘: ‘{"name": "張三","password":"123456"}‘, ‘expect_res‘: ‘<h1>登錄成功</h1>‘}

用例中使用方法
test_user_login.py 部分

import unittest
import requests
from read_excel import *  # 導入read_excel中的方法
import json  # 用來轉化excel中的json字符串為字典

class TestUserLogin(unittest.TestCase):
    @classmethod
    def setUpClass(cls):   # 整個測試類只執行一次
        cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin")  # 讀取該測試類所有用例數據
        # cls.data_list 同 self.data_list 都是該類的公共屬性

    def test_user_login_normal(self):
        case_data = get_test_data(self.data_list, ‘test_user_login_normal‘)   # 從數據列表中查找到該用例數據
        if not case_data:   # 有可能為None
            print("用例數據不存在")
        url = case_data.get(‘url‘)   # 從字典中取數據,excel中的標題也必須是小寫url
        data = case_data.get(‘data‘)  # 註意字符串格式,需要用json.loads()轉化為字典格式
        expect_res = case_data.get(‘expect_res‘)  # 期望數據

        res = requests.post(url=url, data=json.loads(data))  # 表單請求,數據轉為字典格式
        self.assertEqual(res.text, expect_res)  # 改為assertEqual斷言

if __name__ == ‘__main__‘:   # 非必要,用於測試我們的代碼
    unittest.main(verbosity=2)

test_user_reg.py部分

import unittest
import requests
from db import *
from read_excel import *
import json

class TestUserReg(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserReg")  # 讀取TestUserReg工作簿的所有數據

    def test_user_reg_normal(self):
        case_data = get_test_data(self.data_list, ‘test_user_reg_normal‘)
        if not case_data:
            print("用例數據不存在")
        url = case_data.get(‘url‘)
        data = json.loads(case_data.get(‘data‘))  # 轉為字典,需要取裏面的name進行數據庫檢查
        expect_res = json.loads(case_data.get(‘expect_res‘))  # 轉為字典,斷言時直接斷言兩個字典是否相等
        name = data.get("name")  # 範冰冰

        # 環境檢查
        if check_user(name):
            del_user(name)
        # 發送請求
        res = requests.post(url=url, json=data)  # 用data=data 傳字符串也可以
        # 響應斷言(整體斷言)
        self.assertDictEqual(res.json(), expect_res)
        # 數據庫斷言
        self.assertTrue(check_user(name))
        # 環境清理(由於註冊接口向數據庫寫入了用戶信息)
        del_user(name)

if __name__ == ‘__main__‘:    # 非必要,用於測試我們的代碼
    unittest.main(verbosity=2)  

增加log功能

新建config.py文件

import logging

logging.basicConfig(level=logging.DEBUG,  # log level
                    format=‘[%(asctime)s] %(levelname)s [%(funcName)s: %(filename)s, %(lineno)d] %(message)s‘,  # log格式
                    datefmt=‘%Y-%m-%d %H:%M:%S‘,  # 日期格式
                    filename=‘log.txt‘,  # 日誌輸出文件
                    filemode=‘a‘)  # 追加模式

if __name__ == ‘__main__‘:
    logging.info("hello")

運行後在當前目錄下生成log.txt,內容如下:

[2018-09-11 18:08:17] INFO [<module>: config.py, 38] hello

Log Level:

  • CRITICAL: 用於輸出嚴重錯誤信息
  • ERROR: 用於輸出錯誤信息
  • WARNING: 用於輸出警示信息
  • INFO: 用於輸出一些提升信息
  • DEBUG: 用於輸出一些調試信息

優先級 CRITICAL > ERROR > WARNING > INFO > DEBUG
指定level = logging.DEBUG所有等級大於等於DEBUG的信息都會輸出
若指定level = logging.ERROR WARNING,INFO,DEBUG小於設置級別的信息不會輸出

日誌格式:

  • %(levelno)s: 打印日誌級別的數值
  • %(levelname)s: 打印日誌級別名稱
  • %(pathname)s: 打印當前執行程序的路徑,其實就是sys.argv[0]
  • %(filename)s: 打印當前執行程序名
  • %(funcName)s: 打印日誌的當前函數
  • %(lineno)d: 打印日誌的當前行號
  • %(asctime)s: 打印日誌的時間
  • %(thread)d: 打印線程ID
  • %(threadName)s: 打印線程名稱
  • %(process)d: 打印進程ID
  • %(message)s: 打印日誌信息
    項目使用log
    將所有print改為log,如db.py 部分
import pymysql
from config import *

# 封裝數據庫查詢操作
def query_db(sql):
    conn = get_db_conn()
    cur = conn.cursor()  
    logging.debug(sql)    # 輸出執行的sql
    cur.execute(sql)
    conn.commit()
    result = cur.fetchall() 
    logging.debug(result)  # 輸出查詢結果
    cur.close() 
    conn.close() 
    return result 

# 封裝更改數據庫操作
def change_db(sql):
    conn = get_db_conn() 
    cur = conn.cursor()
    logging.debug(sql)  # 輸出執行的sql
    try:
        cur.execute(sql) 
        conn.commit() 
    except Exception as e:
        conn.rollback() 
        logging.error(str(e))  # 輸出錯誤信息
    finally:
        cur.close() 
        conn.close()

用例中使用

import unittest
import requests
from read_excel import *  # 導入read_excel中的方法
import json  # 用來轉化excel中的json字符串為字典
from config import *

class TestUserLogin(unittest.TestCase):
    @classmethod
    def setUpClass(cls):   # 整個測試類只執行一次
        cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin")  # 讀取該測試類所有用例數據
        # cls.data_list 同 self.data_list 都是該類的公共屬性

    def test_user_login_normal(self):
        case_data = get_test_data(self.data_list, ‘test_user_login_normal‘)   # 從數據列表中查找到該用例數據
        if not case_data:   # 有可能為None
            logging.error("用例數據不存在")
        url = case_data.get(‘url‘)   # excel中的標題也必須是小寫url
        data = case_data.get(‘data‘)  # 註意字符串格式,需要用json.loads()轉化為字典格式
        expect_res = case_data.get(‘expect_res‘)  # 期望數據

        res = requests.post(url=url, data=json.loads(data))  # 表單請求,數據轉為字典格式
        logging.info("測試用例:{}".format(‘test_user_login_normal‘))
        logging.info("url:{}".format(url))
        logging.info("請求參數:{}".format(data))
        logging.info("期望結果:{}".format(expect_res))
        logging.info("實際結果:{}".format(res.text)
        self.assertEqual(res.text, expect_res)  # 斷言

if __name__ == ‘__main__‘:
    unittest.main(verbosity=2)

項目下log.txt輸出結果:

[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 8] 測試用例:test_user_login_normal
[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 9] url:http://115.28.108.130:5000/api/user/login/
[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 10] 請求參數:{"name": "張三","password":"123456"}
[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 11] 期望結果:<h1>登錄成功</h1>
[2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 12] 實際結果:<h1>登錄成功</h1>

因為每個用例都要輸出很多log信息,我們封裝一個case_log的函數
項目下新建case_log.py

from config import *
import json

def log_case_info(case_name, url, data, expect_res, res_text): 
    if isinstance(data,dict):
        data = json.dumps(data, ensure_ascii=False)  # 如果data是字典格式,轉化為字符串
    logging.info("測試用例:{}".format(case_name))
    logging.info("url:{}".format(url))
    logging.info("請求參數:{}".format(data))
    logging.info("期望結果:{}".format(expect_res))
    logging.info("實際結果:{}".format(res_text)

簡化後的用例log輸出

import unittest
import requests
from read_excel import *  
import json
from config import *
from case_log import log_case_info  # 導入方法

class TestUserLogin(unittest.TestCase):
    @classmethod
    def setUpClass(cls):  
        cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin") 

    def test_user_login_normal(self):
        case_data = get_test_data(self.data_list, ‘test_user_login_normal‘) 
        if not case_data: 
            logging.error("用例數據不存在")
        url = case_data.get(‘url‘)  
        data = case_data.get(‘data‘) 
        expect_res = case_data.get(‘expect_res‘)

        res = requests.post(url=url, data=json.loads(data))
        log_case_info(‘test_user_login_normal‘, url, data, expect_res, res_text)  # 輸出用例log信息
        self.assertEqual(res.text, expect_res)  

if __name__ == ‘__main__‘:
    unittest.main(verbosity=2)

發送郵件

在生成報告後我們希望框架能自動把報告發送到我們的郵箱中。和outlook,foxmail等郵件客戶端一樣,Python中發送郵件需要通過Email的smtp服務發送。

首先需要確認用來發送郵件的郵箱是否啟用了smtp服務

發送郵件分3步

  1. 編寫郵件內容(Email郵件需要專門的MIME格式)
  2. 組裝Email頭(發件人,收件人,主題)
  3. 連接smtp服務器並發送郵件
import smtplib  # 用於建立smtp連接
from email.mime.text import MIMEText  # 郵件需要專門的MIME格式

# 1. 編寫郵件內容(Email郵件需要專門的MIME格式)
msg = MIMEText(‘this is a test email‘, ‘plain‘, ‘utf-8‘)  # plain指普通文本格式郵件內容

# 2. 組裝Email頭(發件人,收件人,主題)
msg[‘From‘] = ‘[email protected]‘  # 發件人
msg[‘To‘] = ‘[email protected]‘  # 收件人
msg[‘Subject‘] = ‘Api Test Report‘  # 郵件主題

# 3. 連接smtp服務器並發送郵件
smtp = smtplib.SMTP_SSL(‘smtp.sina.com‘)  # smtp服務器地址 使用SSL模式
smtp.login(‘[email protected]‘, ‘hanzhichao123‘)  # 用戶名和密碼
smtp.sendmail("[email protected]", "[email protected]", msg.as_string())
smtp.quit()

中文郵件主題、HTML郵件內容,及附件

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart  # 混合MIME格式,支持上傳附件
from email.header import Header  # 用於使用中文郵件主題

# 1.  編寫郵件內容
with open(‘report.html‘, encoding=‘utf-8‘) as f:  # 打開html報告
    email_body = f.read()  # 讀取報告內容

msg = MIMEMultipart()  # 混合MIME格式
msg.attach(MIMEText(email_body, ‘html‘, ‘utf-8‘))  # 添加html格式郵件正文(會丟失css格式)

# 2. 組裝Email頭(發件人,收件人,主題)
msg[‘From‘] = ‘[email protected]‘  # 發件人
msg[‘To‘] = ‘[email protected]‘  # 收件人
msg[‘Subject‘] = Header(‘接口測試報告‘, ‘utf-8‘)  # 中文郵件主題,指定utf-8編碼

# 3. 構造附件1,傳送當前目錄下的 test.txt 文件
att1 = MIMEText(open(‘report.html‘, ‘rb‘).read(), ‘base64‘, ‘utf-8‘)  # 二進制格式打開
att1["Content-Type"] = ‘application/octet-stream‘
att1["Content-Disposition"] = ‘attachment; filename="report.html"‘  # filename為郵件中附件顯示的名字
msg.attach(att1)

# 4. 連接smtp服務器並發送郵件
smtp = smtplib.SMTP_SSL(‘smtp.sina.com‘)  # smtp服務器地址 使用SSL模式
smtp.login(‘[email protected]‘, ‘hanzhichao123‘)  # 用戶名和密碼
smtp.sendmail("[email protected]", "[email protected]", msg.as_string())
smtp.sendmail("[email protected]", "[email protected]", msg.as_string())  # 發送給另一個郵箱
smtp.quit()

封裝發送郵件方法

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart  # 混合MIME格式,支持上傳附件
from email.header import Header  # 用於使用中文郵件主題
from config import *


def send_email(report_file):
    msg = MIMEMultipart()  # 混合MIME格式
    msg.attach(MIMEText(open(report_file, encoding=‘utf-8‘).read(), ‘html‘, ‘utf-8‘))  # 添加html格式郵件正文(會丟失css格式)

    msg[‘From‘] = ‘[email protected]‘  # 發件人
    msg[‘To‘] = ‘[email protected]‘  # 收件人
    msg[‘Subject‘] = Header(‘接口測試報告‘, ‘utf-8‘)  # 中文郵件主題,指定utf-8編碼

    att1 = MIMEText(open(report_file, ‘rb‘).read(), ‘base64‘, ‘utf-8‘)  # 二進制格式打開
    att1["Content-Type"] = ‘application/octet-stream‘
    att1["Content-Disposition"] = ‘attachment; filename="report.html"‘  # filename為郵件中附件顯示的名字
    msg.attach(att1)

    try:
        smtp = smtplib.SMTP_SSL(‘smtp.sina.com‘)  # smtp服務器地址 使用SSL模式
        smtp.login(‘[email protected]‘, ‘hanzhichao123‘)  # 用戶名和密碼
        smtp.sendmail("[email protected]", "[email protected]", msg.as_string())
        smtp.sendmail("[email protected]", "[email protected]", msg.as_string())  # 發送給另一個郵箱
        logging.info("郵件發送完成!")
    except Exception as e:
        logging.error(str(e))
    finally:
        smtp.quit()

run_all.py中結束後發送郵件

import unittest
from HTMLTestReportCN import HTMLTestRunner
from config import *
from send_email import send_email

logging.info("================================== 測試開始 ==================================")
suite = unittest.defaultTestLoader.discover("./")

with open("report.html", ‘wb‘) as f:  # 改為with open 格式
    HTMLTestRunner(stream=f, title="Api Test", description="測試描述", tester="卡卡").run(suite)

send_email(‘report.html‘)  # 發送郵件
logging.info("================================== 測試結束 ==================================")

技術分享圖片

使用配置文件

和項目的log配置一樣,數據庫服務器地址,郵件服務地址我們一般放到配置文件config.py

import logging
import os

# 項目路徑
prj_path = os.path.dirname(os.path.abspath(__file__))  # 當前文件的絕對路徑的上一級,__file__指當前文件

data_path = prj_path  # 數據目錄,暫時在項目目錄下
test_path = prj_path  # 用例目錄,暫時在項目目錄下

log_file = os.path.join(prj_path, ‘log.txt‘)  # 也可以每天生成新的日誌文件
report_file = os.path.join(prj_path, ‘report.html‘)  # 也可以每次生成新的報告

# log配置
logging.basicConfig(level=logging.DEBUG,  # log level
                    format=‘[%(asctime)s] %(levelname)s [%(funcName)s: %(filename)s, %(lineno)d] %(message)s‘,  # log格式
                    datefmt=‘%Y-%m-%d %H:%M:%S‘,  # 日期格式
                    filename=log_file,  # 日誌輸出文件
                    filemode=‘a‘)  # 追加模式


# 數據庫配置
db_host = ‘115.28.108.130‘
db_port = 3306
db_user = ‘test‘
db_passwd = ‘123456‘
db = ‘api_test‘

# 郵件配置
smtp_server = ‘smtp.sina.com‘
smtp_user = ‘[email protected]‘
smtp_password = ‘hanzhichao123‘

sender = smtp_user  # 發件人
receiver = ‘[email protected]‘  # 收件人
subject = ‘接口測試報告‘  # 郵件主題

修改db.py,send_email.pyrun_all.py等對配置文件的引用
db.py部分

import pymysql
from config import *

# 獲取連接方法
def get_db_conn():
    conn = pymysql.connect(host=db_host,   # 從配置文件中讀取
                           port=db_port,
                           user=db_user,
                           passwd=db_passwd,  # passwd 不是 password
                           db=db,
                           charset=‘utf8‘)  # 如果查詢有中文,需要指定測試集編碼

send_email.py

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header 
from config import *


def send_email(report_file):
    msg = MIMEMultipart()
    msg.attach(MIMEText(open(report_file, encoding=‘utf-8‘).read(), ‘html‘, ‘utf-8‘))

    msg[‘From‘] = ‘[email protected]‘
    msg[‘To‘] = ‘[email protected]‘
    msg[‘Subject‘] = Header(subject, ‘utf-8‘)  # 從配置文件中讀取

    att1 = MIMEText(open(report_file, ‘rb‘).read(), ‘base64‘, ‘utf-8‘)  # 從配置文件中讀取
    att1["Content-Type"] = ‘application/octet-stream‘
    att1["Content-Disposition"] = ‘attachment; filename="{}"‘.format(report_file)  # 參數化一下report_file
    msg.attach(att1)

    try:
        smtp = smtplib.SMTP_SSL(smtp_server)  # 從配置文件中讀取
        smtp.login(smtp_user, smtp_password)  # 從配置文件中讀取
        smtp.sendmail(sender, receiver, msg.as_string())
        logging.info("郵件發送完成!")
    except Exception as e:
        logging.error(str(e))
    finally:
        smtp.quit()

run_all.py

import unittest
from HTMLTestReportCN import HTMLTestRunner
from config import *
from send_email import send_email

logging.info("================================== 測試開始 ==================================")
suite = unittest.defaultTestLoader.discover(test_path)  # 從配置文件中讀取用例路徑

with open(report_file, ‘wb‘) as f:  # 從配置文件中讀取
    HTMLTestRunner(stream=f, title="Api Test", description="測試描述", tester="卡卡").run(suite)

send_email(report_file)  # 從配置文件中讀取
logging.info("================================== 測試結束 ==================================")

框架整理

技術分享圖片
當前所有文件(配置文件,公共方法,測試用例,數據,報告,log)都在項目根目錄下,隨著用例的增加和功能的補充,文件會越來越多,不便於維護和管理,因此我們要建立不同的文件夾,對文件進行分類組織

  1. 在項目中新建以下文件夾:
  • config: 存放項目配置文件
  • data: 存放用例數據文件
  • lib: 公共方法庫
  • log: 存放日誌文件
  • report: 存放報告文件
  • test: 存放測試用例
    • user: 存放user模塊用例 (模塊下要有__init__.py,這樣裏面的用例才能讀取到)
  1. 將配置文件config.py移動到config目錄下,將數據文件test_user_data.xlsx移動到data目錄下,將公共方法db.py send_email.py case_log.py read_excel.py HTMLTestReportCN.py移動到lib目錄下,將測試用例test_user_login.py test_user_reg.py移動到test/user目錄下,保留run_all.py在項目根目錄下,如圖:
    技術分享圖片
  2. 修改配置文件
    config/config.py部分
import logging
import os

# 項目路徑
prj_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 當前文件的上一級的上一級目錄(增加一級)

data_path = os.path.join(prj_path, ‘data‘)  # 數據目錄
test_path = os.path.join(prj_path, ‘test‘)   # 用例目錄

log_file = os.path.join(prj_path, ‘log‘, ‘log.txt‘)  # 更改路徑到log目錄下
report_file = os.path.join(prj_path, ‘report‘, ‘report.html‘)  # 更改路徑到report目錄下
  1. 修改對配置文件及公共方法的引用

    為避免相對路徑導包出錯的問題,我們統一把導包搜索路徑(sys.path)提升到項目根目錄下,如lib/db.py

lib/db.py 部分

import pymysql
import sys
sys.path.append(‘..‘)  # 提升一級到項目更目錄下
from config.config import *  # 從項目根目錄下導入

測試用例test_user_login.py部分

import unittest
import requests
import json
import os  # 增加了一個os,需要用來組裝路徑
import sys
sys.path.append("../..")  # 提升2級到項目根目錄下
from config.config import *  # 從項目路徑下導入
from lib.read_excel import *  # 從項目路徑下導入
from lib.case_log import log_case_info  # 從項目路徑下導入

class TestUserLogin(unittest.TestCase):
    @classmethod
    def setUpClass(cls):   # 整個測試類只執行一次
        cls.data_list = excel_to_list(os.path.join(data_path, "test_user_data.xlsx"),"TestUserLogin")  # 增加data路徑

run_all.py

import unittest
from lib.HTMLTestReportCN import HTMLTestRunner  # 修改導入路徑
from config.config import *  # 修改導入路徑
from lib.send_email import send_email  # 修改導入路徑

logging.info("================================== 測試開始 ==================================")
suite = unittest.defaultTestLoader.discover(test_path)  # 從配置文件中讀取

with open(report_file, ‘wb‘) as f:  # 從配置文件中讀取
    HTMLTestRunner(stream=f, title="Api Test", description="測試描述", tester="卡卡").run(suite)

send_email(report_file)  # 從配置文件中讀取
logging.info("================================== 測試結束 ==================================")
  1. 如果同一文件夾下的方法相互引用(如lib/read_excel.py假如需要引用lib/db.py),也需要采用這種從項目路徑下導入的方式
  2. run_all.py直接在項目路徑下,不需要提升sys.path,無需相對導入我們自己的包時,如read_excel.py,不需要提升
  1. 運行run_all.py,根據log和報告調試代碼,直至所有用例全部通過

    源碼下載鏈接:https://pan.baidu.com/s/1RzwAlUMHwG4FQmeS-yB9rw 密碼:rvq1

此為北京龍騰育才 Python高級自動化(接口測試部分)授課筆記
課程介紹
想要參加現場(北京)/網絡課程的可以聯系作者微信:lockingfree

  1. 高效學習,快速掌握Python自動化所有領域技能
  2. 同步快速解決各種問題
  3. 配套實戰項目練習

Python接口測試實戰4(上) - 接口測試框架實戰