Pytest進階使用

2022-10-16 12:02:53

fixture

特點:

  • 命令靈活:對於setup,teardown可以省略

  • 資料共用:在conftest.py設定裡寫方法可以實現資料共用,不需要import匯入,可以跨檔案共用

  • scope的層次及神奇的yield組合相當於各種setup和teardown

  • 實現引數化

應用

  • 場景:

測試用例執行時,有的用例需要登入才能執行,有些用例不需要登入。

setup和teardown無法滿足這種情況,但是fixture可以。預設scope(範圍):function

  • 步驟:

    • 匯入pytest

    • 在登入的函數上新增@pytest.fixture()

    • 在要使用的測試方法中傳入(登入函數名稱)

    • 不傳入的就不登入,直接執行測試方法。

fixture作用域

取值 範圍 說明
function 函數級 每一個函數或方法都會呼叫
class 類級別 每個測試類只執行一次
module 模組級 每個.py檔案呼叫一次
package 包級 每個python包只呼叫一次(暫不支援)
session 對談 每次對談只需要執行一次,對談內所有方法及類,模組都共用這個方法
  • session是在整個專案中只執行一次的程式碼

yield關鍵字

  • 場景:

你已經可以將測試方法【前要執行的或依賴的】解決了,那測試方法後銷燬清除資料要如何進行?

  • 解決:

通過在fixture函數中加入yield關鍵字,yield是呼叫第一次返回結果,第二次執行它下面的語句返回。

  • 步驟:

@pytest.fixture(scope=module)

在登入的方法中加yield,之後加銷燬清除的步驟

import pytest
 
@pytest.fixture()
def login():
    # setup
    token = '1235236fdg'
    print("登入功能")
    yield token# 相當於return 返回none
    # teardown
    print("退出登入操作")
 
def test_search():
    print("搜尋功能")
 
def test_cart(login):
    print(f"token:{login}")
    print("購物車")

資料共用

  • 場景:

你與其他工程師合作一起開發時,公共的模組要在不同檔案中,要在大家都存取的到的地方

  • 解決:

使用conftest.py這個檔案進行資料共用,並且它可以放在不同位置起著不同的範圍共用作用

  • 前提:

    • conftest檔名不能換

    • 放在專案下是全域性的資料共用

  • 執行:

    • 系統執行到引數login時先從本模組中查詢是否有這個名字的變數之類的

    • 之後在conftest.py中找是否含有

  • 步驟:

將登入模組帶@pytest.fixture寫在conftest.py

自動應用

  • 場景:

不想原測試方法有任何改動,或全部都自動實現自動應用,沒特例,也都不需要返回值時可以選擇自動應用的方法

  • 解決:

使用fixture中的引數autouse=True實現

  • 步驟:

在方法上面加@pytest.fixture(autouse=Ture)

引數化

  • 場景:

測試離不開資料,為了資料靈活,一般資料都是通過引數傳的

  • 解決:

使用fixture中的固定引數request傳遞

  • 步驟:

在fixture中新增@pytest.fixture(params=[1,2,3,'linda'])

在方法引數寫request,方法體裡面使用request.param接受引數

@pytest.fixture(params=['hogwarts','joker'])
def demo_params(request):
    print(f'使用者名稱為:{request.param}')
    return request.param


def test_demo(demo_params):
    print(f"資料為:{demo_params}")
  • 注意:fixture的引數是params,而呼叫的時候是request.param,沒有s

總結:

  • 模擬setup,teardown(一個用例可以參照多個fixture)

  • yield的用法

  • 作用域(session,module,類級別,方法級別)

  • 自動執行(autouse引數)

  • conftest.py用法,一般會把fixture寫在conftest.py檔案中

  • 實現引數化

pytest.ini檔案

  • pytest.ini是pytest的組態檔

  • 可以修改pytest的預設行為

  • 不能使用中文符號,包括漢字,空格 ,引號,冒號等

作用:

  • 修改用例的命名規則

  • 設定紀錄檔格式,比程式碼設定方便很多

  • 新增標籤,防止執行過程報警告錯誤

  • 指定執行目錄

  • 排除搜尋目錄

改變pytest執行規則

[pytest]
;執行check_開頭的所有檔案
python_files = check_* test_*
;執行所有的以Test和Check開頭的類
python_classes = Test* Check*
;執行所有以test_和check_開頭的方法
python_functions = check_* test_*
  • 注意:win系統的pytest.ini檔案不能寫中文,註釋也不行

pytest設定-新增預設引數

addopts = -v -s --alluredir=./results

指定/忽略執行目錄

;設定執行得路徑
;testpaths = bilibili baidu
;忽略某些資料夾/目錄
norecursedirs = result logs datas test_demo*

外掛開發

  • pytest外掛分類

    • 外部外掛:pip install 安裝的外掛

    • 本地外掛:pytest自動模組發現機制(conftest.py存放的)

    • 內建外掛:程式碼內部的_pytest目錄載入(hook函數)

官網:https://pypi.org/

常用外掛

每一種測試框架收集測試用例的順序是不一樣的

pytest執行順序控制

  • 場景:

對於整合測試,經常會有上下文依賴關係的測試用例。如十個步驟,拆分成十個case,這時候能知道到底執行到哪步報錯。

用例預設執行順序:自上而下執行

  • 解決:

可以通過setup,teardown和fixture來解決,也可以使用pytest-ordering外掛來解決

  • 安裝:pip install pytest-ordering

  • 用法:@pytest.mark.run(order=2)

  • 注意:多個外掛裝飾器(>2)的時候,有可能會發生衝突

並行與分散式並行執行(xdist)

場景1:

  • 測試用例1000條,一個用例執行1分鐘,一個測試人員需要1000分鐘,通常我們會用人力成本換取時間成本,加幾個人一起執行,時間就會縮短。這就是一種分散式場景。

場景2:

  • 假設有個報名系統,對報名總數進行統計,資料同時進行修改操作的時候有可能出現問題,需要模擬這個場景,需要多使用者並行請求資料

解決:

  • 使用分散式並行執行測試用例,分散式外掛:pytest-xdist

  • 安裝:pip install pytest-xdist

  • 注意:用例多的時候效果明顯,多程序並行執行,同時支援allure

hook函數

1. 介紹

  • 是個函數,在系統訊息觸發時被系統呼叫

  • 自動觸發機制

  • Hook函數的名稱是確定的

  • pytest有非常多的hook函數

  • 使用時直接編寫函數體

  • 執行是有先後順序的

  • 可以在不同階段實現不同的功能

pytest執行過程

執行順序:

pytest編寫外掛1-修改預設編碼

pytest_collection_modifyitems收集上來的測試用例實現客製化化功能

解決問題:

  • 自定義用例的執行順序

  • 解決編碼問題(中文的測試用例名稱)

  • 自動新增標籤

from typing import List


# 修改編碼的hook函數
def pytest_collection_modifyitems(
    session: "Session", config: "Config", items: List["Item"]
) -> None:
    # items裡的name是測試用例的名字,nodeid是測試用例的路徑
    print(items)
    for item in items:
        # 如果想改變unicode編碼格式的話,需要先encode成utf-8格式的,再decode成unicode-escape就可以了
        item.name = item.name.encode('utf-8').decode('unicode-escape')
        item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')

編寫外掛2-新增命令列引數

# 定義命令列引數的hook函數
def pytest_addoption(parser):
    # group 將下面所有的option都展示在這個group組下
    mygroup = parser.getgroup('hogwarts')
    mygroup.addoption('--env',  # 註冊一個命令列選項
                      default='test',  # 引數的預設值
                      dest='env',  # 儲存的變數,為屬性命令,可以使用option物件存取到這個值
                      help='set your run env')  # 幫助提示,引數的描述資訊


@pytest.fixture(scope='session')
def cmd_option(request):
    # request獲取命令列的引數,config拿到pytest相關設定,getoption拿到命令列引數
    return request.config.getoption('--env')

打包釋出

打包專案構成:

  • 原始碼包

  • setup.py

  • 測試包

from setuptools import setup, find_packages

setup(
    name='pytest_encode',
    url='',
    version='1.0',  # 版本
    author='joker',  # 作者
    author_email='',  # 郵箱
    description='set your encoding and logger',  # 描述用法
    long_description='Show Chinese for you mark.parametrize().',  # 完整描述
    classifiers=[  # 分類索引,pip所屬包的分類,方便在pip官網中搜尋
        'Framework :: Pytest',
        'Programming Language :: Python',
        'Topic :: Software Development :: Testing',
        'Programming Language :: Python :: 3.8',

    ],
    license='proprietary',  # 程式授權資訊
    packages=find_packages(),  # 通過匯入的方式發現當前專案下所有的包
    keywords=[  # 便於pip進行分類
        'pytest', 'py.test', 'pytest_encode'
    ],
    # 需要安裝的依賴
    install_requires=[
        'pytest'
    ],
    # 入口模組,或者入口函數(最重要的)
    entry_points={
        'pytest11': [
            'pytest_encode = pytest_encode.main'
        ]
    },
    zip_safe=False
    # 針對win系統,不設定成false會出錯
)

打包命令

依賴包安裝:

  • pip install setuptools python的包管理工具,負責安裝和釋出,尤其是安裝擁有依賴關係的包

  • pip install wheel 生成 *.whl格式的安裝包,本質上也是一個壓縮包

打包命令:(切到setup.py所在的目錄下執行)

python setup.py sdist bdist_wheel

dist目錄下.whl的檔案,可以通過pip install 下載

釋出命令

  • python3 -m pip install --user --upgrade twine ## 安裝twine工具

  • python3 -m twine upload --repository testpypi dist/* ## 上傳程式碼