python測試框架-pytest

稀飯配菜根發表於2022-01-18

一、pytest 介紹、執行、引數化和資料驅動、Fixture

pytest安裝與介紹

為何選擇pytest

  • 相容unittest
  • 定製化外掛開發

pycharm 配置github

  • VSC--Git--Remotes...

pycharm pytest 配置

  • settings--搜尋pytest--Python integrated Tools--testing--選擇pytest:根據黃色歎號fix安裝pytest安裝到環境

pytest命名規則

pytest執行測試用例

1 - pycharm

2 - 命令列執行方式 - 推薦(以便後續持續整合)

可能會遇到的找不到模組的路徑問題,需要在導包之前引入路徑 import sys sys.path.append('路徑')

  • 執行包: pytest (pytest會自動檢索當前目錄下所有符合規則的測試用例)
  • 執行一個模組:pytest -vs test.py
  • 只執行某一條測試用例:pytest 目錄/模組.py::類名::用例名
常用命令列引數
  • pytest --help: 獲取所有引數列表
  • -x: 用例一旦失敗(fail/error),就立刻停止
    • 使用場景:一般用於冒煙測試
      • 冒煙測試最早由google提出的一個概念,一般針對每日構建的版本,對系統的基本功能進行簡單測試的測試型別,主要強調程式主體的功能
  • --maxfail=num: 用例達到最大數num停止執行
  • -m: 標記用例
  • -k: 執行包含某個關鍵字的測試用例
  • -v: 列印詳細日誌
  • -s 列印輸出日誌(一般-vs一塊使用)
  • --collect-only:(測試平臺,pytest 自動匯入功能)

標記測試用例:mark

  • 場景:只執行符合要求的某一部分用例,把專案分為多個模組,然後指定模組名稱執行
  • 解決:在測試用例的上方加上pytest裝飾器:@pytest.mark.標籤名
  • 執行 -m 標記自定義的相關用例
    • pytest -s test_mark.py -m=標籤名
    • pytest -s test_mark.py -m 標籤名
    • pytest -s test_mark.py -m "not 標籤名" (not:邏輯運算,表示不是標籤名的都去執行)

跳過(skip)及預期失敗(xfail)

pytest的內建標籤,可以處理一些特殊的、及不能成功的測試用例

  • ship: 始終跳過該用例

    • 方式1: @pytest.mark.skp(reason="程式碼沒有實現")
    • 方式2:在測試用程式碼中新增判斷的語句
      def test_demo():
      	if not login():
      		pytest.skip("未登入無法執行該用例")
      
  • skipif: 遇到特定情況跳過該測試用例,需要給定條件

    @pytest.mark.skipif(條件="", reason="列印提示資訊內容")
    

    image

  • xfail: 遇到特殊情況,產生一個“期望失敗”輸出

執行結果分析

  • 常用:fail error pass
  • 特殊結果:
    • warning
    • deselect

pytest常用執行引數

----------

更多用法使用 pytest --help 檢視幫助文件

用例匹配:

  • pytest -k "add" 匹配所有用例名稱中包含add的用例
  • pytest -m mark 標籤名、標記:在測試用例上新增裝飾器 @pytest.mark.login
    • pytest有很多自帶的標籤,我們自己定的標籤,如login 他會不識別,所以在執行後會有 deselected、warnings
      警告資訊,需要建立pytest配置檔案:pytest.ini

      pytest.ini
      
      [pytest]
      # markers 幫助文件解釋:為你的測試用例新增標籤
      markers = login
              search
              '個人中心'
      
  • pytest --junitxml=./result.xml 生成執行結果檔案
  • pytest --setup-show 回溯fixture的執行過程

pytest.ini:

  • pytest.ini是pytest的配置檔案
    • 檔案內容要以 [pytest] 開頭
    • 修改pytest模組名、類名、用例名稱規則(以什麼開頭:如pytest檔名和用例名預設以test_* 開頭或結尾)
      • python_files (args):用於Python測試模組發現的全域性樣式檔案模式(檔名)

      • python_classes (args):字首或glob名稱,用於發現Python測試類(類名)

      • python_functions (args): Python測試函式和方法發現的字首或glob名稱(方法名)

      • addopts:新增一個或多個命令列引數,如,新增 -vs 命令引數後:執行pytest test_case.py 等同於 pytest -vs test_case.py

        pytest.ini

        [pytest]
        # 為測試用例新增標籤
        markers = login
                  search
        
        # 修改pytest模組名、類名、用例名稱規則(以什麼開頭:如pytest檔名和用例名預設以test_* 開頭或結尾)
        pytest_files = test_* *_test check_*
        pytest_functions = test_* *_test check_*
        
        # 新增一個或多個命令列引數,如,新增 -vs 命令引數後:執行pytest test_case.py  等同於 pytest -vs test_case.py
        addopts = -vs --alluredir=./result
        

pytest框架結構

  • setup() teardown() 類方法執行前後被呼叫
    • 模組級別:setup_module/teardown_module 全域性的、優先順序最高
    • 函式級別:setup_function/teardown_function 只在函式用例生效(與方法的級的區別:不在類中)
    • 類級別:setup_class/teardown_class 只在類中前後執行一次(在類中)
    • 方法級別:setup_method/teardown_method 開始與方法的始末、每個方法執行強後都執行一遍(與函式級別的區別:方法在類中,函式不在類中)

pytest引數化與資料驅動

  • 引數化一般與資料驅動一起使用,
    • 引數化:將變化的測試資料以引數的形式傳入到測試方法,待測試的輸入和輸出是一組資料,可以把測試資料組織起來,用不同的測試資料呼叫相同的測試方法
    • 資料驅動:資料的改變從而驅動自動化的執行,最終引起測試結果的改變,測試資料的資料驅動、測試步驟的資料驅動、配置的資料驅動、po的資料驅動

pytest引數化

  • pytest自帶引數化概念
    • 加入引數化裝飾器:@pytest.mark.parametrize("a, b, result", [1, 2, 3], [2, 3, 5], [0.3, 1, 1.3])
      • ids引數:定義每一組測試資料生成的測試用例的別名,多少組資料就對應有多少個ids
import pytest
import yaml


def add(a, b):
    return a + b


class TestDate:
    @pytest.mark.parametrize("a, b", [(10, 20), (10, 30), (2, 6)])
    def test_param(self, a, b):
         print(a + b)

    @pytest.mark.parametrize(["x", "y"], [(10, 20), (10, 30)])
    def test_param2(self, x, y):
        # print(x + y)
        print(add1(x, y))

    @pytest.mark.parametrize("a", "b", yaml.safe_load(open(r'E:\data.yaml')))
    def test_param5(self, a, b):
        print(f'相加等於{add(a, b)}')
  • 執行用例test_parm會得出三條測試用例資料:
    image

pytest異常捕獲

設計測試用例的時候要儘可能的區分型別,比如除數為0時,預期結果是丟擲異常,則此用例pass,所以使用pytest捕獲ZeroDivisionError異常,如果捕獲到,則不報出異常 則此測試用例通過

with pytest.raises(ZeroDivisionError, TypeError):

fixture高階用法

fixture 介紹:

  • 官網 Features--Modular有詳細介紹
  • fixture又名測試樁子,類似setup teardown
  • fixture 能做到setup teardown 做不到的事情
    • 比如:一個模組裡又很多用例,這些方法有的需要的前置條件不一樣,如有的需要登入,有的不需要登入

      def login():
        print('登入')
      
      def test_search():
        print('搜尋')
      
      def test_search():
        print('購物')
      
      def test_search():
        print('下單')
      
    • 如,如果使用setup teardown 只能是用例前後被呼叫,但是去搜尋,首先不需要登入,所以就可以把login定義為fixture函式,然後傳入到測試方法裡
      使用方法:在被重複呼叫的方法上加上@pytest.fixture()裝飾器,如果某個方法需要登入,就傳入login

      @pytest.fixture()
      def login():
        print('登入')
      
      def test_search():
        print('搜尋')
      
      def test_search(login):
        print('購物')
      
      def test_search(login):
        print('下單')
      
    • 在命令列中使用執行回溯,可以看到fixture執行的詳細過程:pytest test_case.py --setup-show

fixture 作用

  • Fixture是在測試函式執行前後,由pytest執行的外殼函式,程式碼可以定製,滿足多變的測試需求,功能包括:
    • 定於傳入測試中的資料集
    • 配置測試前系統的初始狀態
    • 為批量測試提供資料來源等
  • Fixture是pytest用於將測試前後進行預備,清理工作的程式碼分類核心測試邏輯的一種機制

fixture用法

  • 1- 類似setup teardown功能,但比setup teardown更靈活
  • 2- 直接通過函式名呼叫或者裝飾去@pytest.mark.usefixtures('test1')
  • 3- 允許使用多個Fixture
  • 4- 使用autouse自動應用,如果由返回值,需要穿fixture函式名
  • 5- 作用域 session>module>class>function

使用-- setup-show 回溯fixture的執行過程

  • pytest test_case.py --setup-show

pytest yield

  • 以上fixture記錄的僅僅是setup,即測試用例執行前的操作,如果需要加上teardown的操作,需要在fixture函式中加入 yield

    @pytest.fixture()
        def login():
          print('登入') # 用例執行前登入
          yield # 相當與 return 可以返回一些資料  如 yield token
          print('退出') # 用例結束後退出
    

conftest + fixture

  • conftest.py檔案,它主要是實現資料(fixture)共享的檔案,名字是固定的。

    • 1- 第一,conftest.py檔案當中,它儲存的都是fixture,就是給用例提供做前置準備工作和後置清理工作的一個東西;
    • 2- 第二,conftest.py檔案可以將它的fixtures共享到它自己目錄下的所有用例,用例當中如果使用fixture的話,是不需用匯入conftest.py這個檔案的,會直接自動去查詢;
    • 3- 第三,conftest.py它是屬於層級共享的,也就是說,一個自動化專案當中,可以在不同的包下面去建立conftest.py這個檔案。
  • 執行原則:就近原則,如果當前包下沒有conftest.py就會往上一層找

fixture 引數化


二、常用外掛、資料驅動、編寫pytest外掛、Allure

pytest常用外掛

pip install pytest-ordering:控制用例的執行順序

  • 建議在編寫測試用例的時候,能不讓用例順序執行就不順序執行,這樣可能會更好的暴露出問題
  • 在測試方法上加上裝飾器:@pytest.mark.run(order=2)

pip install pytest-dependency:控制用例的依賴關係

ps:設計測試用例的時候進可能不要讓用例有順序,不要讓測試用例有依賴關係,如果無法做到,可以臨時的用外掛解決

  • 官網 : https://pytest-dependency.readthedocs.io/en/latest/usage.html#basic-usage

  • 設定一個用例和一個用例的依賴關係:一旦用例A失敗,那麼用例B也不會執行。比如:用例A為新增購物車,用例B為去結算,那麼如果用例A沒有登入就會執行失敗,則用例B也就會執行失敗
    pytest-dependency 要做的就是,讓他們之間存在一種依賴關係:一旦用例A失敗,那麼用例B也不會執行 SKIP

    import pytest
    # 官方demo:
    
    @pytest.mark.dependency()   # test_a測試用例設定了dependency依賴關係
    @pytest.mark.xfail(reason="deliberate fail")
    def test_a():
      assert False
    
    @pytest.mark.dependency()  # test_b測試用例設定了dependency依賴關係
    def test_b():
      pass
    
    @pytest.mark.dependency(depends=["test_a"])  # test_c 依賴於測試用例 test_a。 因為test_a斷言失敗,所以test_c會跳過
    def test_c():
      pass
    
    
    @pytest.mark.dependency(depends=["test_a"])  # test_d 依賴於測試用 test_b
    def test_d():
      pass
    
    @pytest.mark.dependency(depends=["test_b", "test_c"])  test_e依賴與測試用例 test_b 和 test_c 因為test_b通過了,但test_c跳過,所以test_e也會跳過
    def test_e():
      pass
    

pip install pytest-xdist:分散式併發執行測試用例

  • 機制:哪個cpu先執行完一個任務,就下發另一個任務
    • pytest -n 3 :3=當前系統的cpu個數,如果不知系統有多少個cpu或者不知道可以承載多少個程式,使用 pytest -n aotu 自動分發空閒的程式

pip install pytest-rerunfailures:失敗重跑

  • pytest --reruns 5 : 如果用例失敗,就會重新跑5次
  • pytest --reruns 5 --reruns-delay 2:用例失敗後等待2秒後再執行,或者再用例方法上加上裝飾器@pytest.mark.flaky(5, reruns-delay=2)

pip install pytest-assume:多重校驗

  • 通常一個測試方法中會寫多個斷言,如果第一條斷言過不去,下面的就不執行了,如果我們想報錯也往下執行,使用pytest提供的斷言方法方法
    • pytest.assume(1==4) 相當於 assert 1==4 # 此方法應用場景較少

pip install pytest-random-order:用例隨機執行

  • pytest --random-order-seed= 設定一個種子,使用比較少

pip install pytest-html:測試報告

  • 後續使用allure,不做介紹

三、pytest高階用法 hook函式

pytest外掛載入方式

  • 內建plugin

    • 從程式碼內部的 _pytest 目錄載入
      • External Libraries - site-package - _pytest - hookspec.py
        • hookspec.py 有很多方法 即我們所說的hook方法,我們可以改寫hook方法來滿足我們一些需求
  • 外部外掛(第三方外掛)

  • conftest.py 存放的本地外掛(重點):

    • 自動模組發現機制
  • pytest --trace-config 檢視當前pytest中所有的plugin(帶有hook方法的檔案)

Allure 生成測試報告

另起...

相關文章