接口實戰項目總結上

1. 前程貸業務分析
1.1 平臺介紹

前程貸是一個網貸信息服務平臺,p2p模式,主要業務流程:借款人發佈借款項目,經管理員審覈,進入競標狀態後,投資人選擇可投資項目進行投資。用戶能夠同時爲借款人和投資人。python

用戶模塊:註冊、登陸、充值、提現、更新暱稱、投資、用戶信息,共7個接口mysql

項目模塊:新增項目、審覈項目、分頁獲取項目列表,共3個接口正則表達式

實現5個接口的自動化測試:註冊、登陸、充值、新增項目、投資sql

1.2 數據庫

數據流記錄,5張表數據庫

會員表member,保存平臺會員數據。用戶名、密碼(加密)、手機號、用戶類型、可用餘額、註冊時間json

項目表loan,保存平臺項目數據。借款人id,標題,借款金額,年利率,借款期限、借款期限類型、競標天數、建立時間、競標開始時間、結束時間、項目狀態cookie

投資表invest,保存平臺投資記錄數據,用戶投資後就會在表.;裏新增一條投資數據。投資人id、標id、投資金額、建立時間、是否有效55網絡

回款計劃表repayment,滿標後,每份投資會生成一條或多條回款計劃記錄。session

平臺會員資金流水記錄表,只要會員可用餘額有變更,就會在這個表新增一條記錄。app

1.3 接口信息
  • 接口地址、請求方法、請求頭、請求參數

  • 響應體、接口鑑權等

小結:需求分析中,理解業務邏輯,以及數據流在數據庫中的映射關係,明確每一個接口的信息,包括地址、請求方法、類型、請求參數等

2. 測試用例編寫

excel編寫,一個表單表明一個測試模塊,用例內容包括:用例編號、名稱、接口地址、請求方法、請求參數(json格式)、預期結果、實際結果、是否經過

測試用例的設計方法:等價類劃分、邊界值分析、錯誤推測法(全角字符串、超長混合字符串、數字0、單引號)

總共寫了100多條測試用例。

image-20200910101538677

3. 冒煙測試

使用postman對程序的主要功能進行驗證。

image-20200910102733060

4.分層設計理念+數據驅動思想搭建測試框架
  • 結構清晰:測試用例層(業務層)、配置文件層、數據層、日誌層、報告層、腳本層
image-20200908155321720
  • 減小代碼冗餘:數據驅動思想,測試數據與用例執行邏輯分離,一個測試用例腳本能夠對數據進行批量處理

python + unittest + ddt + requests

import unittest

@ddt.ddt  # 裝飾器,該類範圍內會自動建立多個實例方法
class TestRegister(unittest.TestCase): # 新建一個測試類,並繼承unittest.TestCase父類

    @classmethod
    def setUpClass(cls):  # 初始化全部用例的公共操做,建立請求對象,構造請求參數等
        pass

    @classmethod
    def tearDownClass(cls):  # 用於全部用例的公共資源釋放,例如關閉接口請求會話對象
        pass

    @ddt.data(*testdatas)  # 對序列類型拆包,參數傳遞
    def test_register(self, testcase):  # 測試用例:訪問接口、傳參、獲取響應值、斷言操做
		pass 
   
if __name__ == '__main__':
    unittest.main()  # 依據ACSICC值的順序執行
	# 調整執行順序TestSuit套件,調用addTest方法,TextTestRunner執行套件
5. 接口自動化測試框架的技術點

請求處理、excel用例讀取、配置信息的處理、日誌記錄處理、參數化&正則表達式、數據校驗pymysql、接口依賴處理、unittest單元測試框架、ddt數據驅動、Jenkins單元持續集成等

6.封裝—requests接口請求
import json
import requests

class HttpRequest:

    def __init__(self):
        # 建立會話對象,自動化維護cookie信息
        self.session = requests.Session()

    # 發起請求
    def send(self, method, url, **kwargs):  # 關鍵字參數包括headers、json、cookies等
        method = method.upper()  # 請求方法大寫
        kwargs["json"] = self.handle_param("json", kwargs)
        kwargs["data"] = self.handle_param("data", kwargs)
        return self.session.request(method, url, **kwargs)
    
    # 請求參數處理
    @staticmethod
    def handle_param(param_name, param_dict):
        # 無論輸入的是json格式的字符串,仍是字典字符串,或者是字典,都能轉爲字典輸出
        if param_name in param_dict:
            data = param_dict.get(param_name)
            if isinstance(data, str):
                try:
                    data = json.loads(data)  # 將json字符串(python中格式爲‘{}’)轉換成字典
                except Exception:
                    data = eval(data)  # 直接將字符串最外層的引號拿掉,字典形式
            return data

    # 添加請求頭,公共請求頭更新
    def add_headers(self, one_dict):  # 請求頭參數,字典類型
        self.session.headers.update(one_dict)

    # 關閉會話,釋放資源
    def close(self):
        self.session.close()
7. 封裝—excel數據讀寫
import os
from openpyxl import load_workbook

class Testcase:  # 經過建立不一樣的對象保存每一條測試用例,用例數據經過建立實例屬性來保存,具備全局通用的做用
    pass

class HandleExcel:
    def __init__(self, filename, sheetname=None):
        self.filename = os.path.join(DATA_PATH, filename)
        self.sheetname = sheetname
	
    def read_data(self):
        wb = load_workbook(self.filename)  # 加載excel文件
        if self.sheetname == None:
            ws = wb.active  # 默認讀取第一個表單
        else:
            ws = wb[self.sheetname]  # 獲取指定表單對象
        testcases_list = [] # 存放數據
        headers_list = []  # 存放表頭信息
        for row in range(1, ws.max_row + 1):
            one_testcase = Testcase()  # 建立對象,經過動態建立實例屬性的方法存放每一行用例
            for column in range(1, ws.max_column + 1):
                one_cell = ws.cell(row, column) # 建立單元格對象
                one_cell_value = one_cell.value
                if row == 1:
                    headers_list.append(one_cell_value)
                else:
                    key = headers_list[column - 1]  
                    setattr(one_testcase, str(key), one_cell_value)  # 設置當前用例所對應的表頭屬性
                    if key == "actual":
                        setattr(one_testcase, "actual_column", column)  # 設置存放實際響應報文所在列的列號屬性
                    elif key == "result":
                        setattr(one_testcase, "result_column", column)  # 設置存放用例執行結果所在列的列號屬性
            if row != 1: 
                setattr(one_testcase, "row", row)  # 設置當前用例所在的行號屬性
                testcases_list.append(one_testcase)
        return testcases_list # 列表的元素是對象

    def write_data(self, one_testcase, actual_value, result_value):
        wb = load_workbook(self.filename)  # 加載指定excel文件
        if self.sheetname == None:
            ws = wb.active
        else:
            ws = wb[self.sheetname]  # 訪問表單
        ws.cell(one_testcase.row, one_testcase.actual_column, value=actual_value) # 訪問指定單元格並寫入數據
        ws.cell(one_testcase.row, one_testcase.result_column, value=result_value)  # 寫入狀態時,必定要將excel文件關閉
        wb.save(self.filename) # 對excel文件修改後,必定要保存
8. 封裝—數據庫處理
import random
import pymysql
from scripts.handle_yaml import do_yaml

class HandleMysql:
    def __init__(self):
        # 1.建立鏈接對象
        self.conn = pymysql.connect(host=do_yaml.get_data('mysql', 'host'),
                                    user=do_yaml.get_data('mysql', 'user'),
                                    password=do_yaml.get_data('mysql', 'password'),
                                    port=do_yaml.get_data('mysql', 'port'),
                                    database=do_yaml.get_data('mysql', 'database'),
                                    charset="utf8",  # 注意這裏不能寫成utf-8
                                    cursorclass=pymysql.cursors.DictCursor)
        self.cursor = self.conn.cursor()  # 2.建立遊標對象

    # 3.獲取一條數據,字典類型
    def get_one_value(self, sql, args=None):
        self.cursor.execute(sql, args=args)
        self.conn.commit()
        return self.cursor.fetchone()
	# 4.獲取多條數據,嵌套字典的列表類型
    def get_values(self, sql, args=None):
        self.cursor.execute(sql, args=args)
        self.conn.commit()
        return self.cursor.fetchall()
	# 5.關閉遊標,再關閉鏈接
    def close(self):
        self.cursor.close()
        self.conn.close()

    @staticmethod
    def generate_telephone():
        """
        隨機生成手機號
        手機號規則:前3位—網絡識別號;第4-7位—地區編碼;第8-11位—用戶號碼
        第1位:1;
        第2位:3,4,5,7,8
        第3位:3:【0,9】, 4:【5,7】, 5:【0,9】, 7:【6,7,8】, 8:【0-9】
        :return:返回一個手機號碼
        """
        # 前三位
        second = random.choice([3, 4, 5, 7, 8])
        third = str({
                        3: random.randint(0, 9),
                        4: random.choice([5, 7]),
                        5: random.randint(0, 9),
                        7: random.choice([6, 7, 8]),
                        8: random.randint(0, 9)
                    }[second])
        # 後八位
        eight = ''.join(random.sample('0123456789', 8))
        return '1' + str(second) + third + eight

    # 在數據庫中查詢隨機生成的手機號是否存在
    def check_telephone(self, telephone):
        sql = do_yaml.get_data('mysql', 'select_user_sql')
        if self.get_one_value(sql, args=[telephone]):
            return True
        else:
            return False

    # 獲得一個在數據庫中不存在的手機號
    def get_new_telephone(self):
        while True:
            one_mobile = self.generate_telephone()
            if not self.check_telephone(one_mobile):
                break
        return one_mobile

    def get_not_existed_user_id(self):
        # 從yaml配置文件中獲取查詢最大用戶id的sql語句
        sql = do_yaml.get_data('mysql', 'select_max_user_id_sql')
        # # 獲取最大的用戶id + 1
        not_existed_id = self.get_one_value(sql).get('max(id)') + 1
        return not_existed_id

    def get_not_existed_loan_id(self):
        sql = do_yaml.get_data('mysql', 'select_max_loan_id_sql')
        # # 獲取最大的用戶id + 1
        not_existed_id = self.get_one_value(sql).get('max(id)') + 1
        return not_existed_id
相關文章
相關標籤/搜索