Pytest系列(16)- 分佈式測試插件之pytest-xdist的詳細使用

若是你還想從頭學起Pytest,能夠看看這個系列的文章哦!html

https://www.cnblogs.com/poloyy/category/1690628.htmlpython

 

前言

  • 日常咱們功能測試用例很是多時,好比有1千條用例,假設每一個用例執行須要1分鐘,若是單個測試人員執行須要1000分鐘才能跑完
  • 當項目很是緊急時,會須要協調多個測試資源來把任務分紅兩部分,因而執行時間縮短一半,若是有10個小夥伴,那麼執行時間就會變成十分之一,大大節省了測試時間
  • 爲了節省項目測試時間,10個測試同時並行測試,這就是一種分佈式場景
  • 一樣道理,當咱們自動化測試用例排常多的時候, 一條條按順序執行會很是慢,pytest-xdist的出現就是爲了讓自動化測試用例能夠分佈式執行,從而節省自動化測試時間
  • pytest-xdist是屬於進程級別的併發

 

分佈式執行用例的設計原則(重中之重的重點)

  • 用例之間是獨立的,用例之間沒有依賴關係,用例能夠徹底獨立運行【獨立運行】
  • 用例執行沒有順序,隨機順序都能正常執行【隨機執行】
  • 每一個用例都能重複運行,運行結果不會影響其餘用例【不影響其餘用例】

 

插件安裝

pip3 install pytest-xdist -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

 

pytest-xdist經過一些獨特的測試執行模式擴展了pytest

  • 測試運行並行化:若是有多個CPU或主機,則能夠將它們用於組合的測試運行。 這樣能夠加快開發速度或使用遠程計算機的特殊資源。
  • --looponfail:在子進程中重複運行測試。 每次運行以後,pytest都會等到項目中的文件更改後再運行以前失敗的測試。 重複此過程,直到全部測試經過,而後再次執行完整運行。
  • 跨平臺覆蓋:您能夠指定不一樣的Python解釋程序或不一樣的平臺,並在全部這些平臺上並行運行測試。

  

快速入門

這是運行代碼的包結構web

14xdist是項目文件夾名稱
│  conftest.py
│  test_1.py
│  __init__.py
│              
├─test_51job
│  │  conftest.py
│  │  test_case1.py
│  │  __init__.py 
│          
├─test_toutiao
│  │  test_case2.py
│
├─test_weibo
│  │  conftest.py
│  │  test_case3.py
│  │  __init__.py 
│          

具體代碼

最外層的conftest.py

# 外層conftest.py

@pytest.fixture(scope="session")
def login():
    print("====登陸功能,返回帳號,token===")
    name = "testyy"
    token = "npoi213bn4"
    yield name, token
    print("====退出登陸!!!====")
View Code

 

最外層的test_1.py

import pytest


@pytest.mark.parametrize("n", list(range(5)))
def test_get_info(login, n):
    sleep(1)
    name, token = login
    print("***基礎用例:獲取用戶我的信息***", n)
    print(f"用戶名:{name}, token:{token}")
View Code

 

test_51job包下的conftest.py

import pytest


@pytest.fixture(scope="module")
def open_51(login):
    name, token = login
    print(f"###用戶 {name} 打開51job網站###")
View Code

 

test_51job包下的test_case1.py

from time import sleep

import pytest


@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
    sleep(1)
    print("51job,列出全部職位用例", n)


@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
    sleep(1)
    print("51job,找出全部python崗位", n)
View Code

 

test_toutiao包下的test_case2.py

from time import sleep

import pytest


@pytest.mark.parametrize("n", list(range(5)))
def test_no_fixture(login, n):
    sleep(1)
    print("==沒有__init__測試用例,我進入頭條了==", login)
View Code

 

test_weibo包下的conftest.py

import pytest


@pytest.fixture(scope="function")
def open_weibo(login):
    name, token = login
    print(f"&&& 用戶 {name} 返回微博首頁 &&&")
View Code

 

test_weibo包下的test_case3.py

from time import sleep

import pytest


@pytest.mark.parametrize("n", list(range(5)))
class TestWeibo:
    def test_case1_01(self, open_weibo, n):
        sleep(1)
        print("查看微博熱搜", n)

    def test_case1_02(self, open_weibo, n):
        sleep(1)
        print("查看微博范冰冰", n)
View Code

 

不使用分佈式測試的命令和所需執行時間

pytest -s

 

能夠看到,執行一條用例大概1s(由於每一個用例都加了 sleep(1) ),一共30條用例,總共運行30s;那麼若是有1000條用例,執行時間就真的是1000ssession

 

使用分佈式測試的命令和所需執行時間

pytest -s -n auto

 

知識點

  • 能夠看到,最終運行時間只須要6s,個人電腦是真6核,假12核
  • -n auto:能夠自動檢測到系統的CPU核數;從測試結果來看,檢測到的是邏輯處理器的數量,即假12核
  • 使用auto等於利用了全部CPU來跑用例,此時CPU佔用率會特別高

 

能夠指定須要多少個CPU來跑用例

pytest -s -n 2

 

pytest-xdist是能夠和pytest-html很好的相結合

pytest -s -n auto --html=report.html --self-contained-html

 

pytest-xdist按照必定的順序執行

 pytest-xdist默認是無序執行的,能夠經過 --dist 參數來控制順序併發

 --dist=loadscope 分佈式

  • 將按照同一個模塊module下的函數和同一個測試類class下的方法來分組,而後將每一個測試組發給能夠執行的worker,確保同一個組的測試用例在同一個進程中執行
  • 目前沒法自定義分組,按類class分組優先於按模塊module分組

 

 --dist=loadfile ide

按照同一個文件名來分組,而後將每一個測試組發給能夠執行的worker,確保同一個組的測試用例在同一個進程中執行函數

 

如何讓scope=session的fixture在test session中僅僅執行一次

pytest-xdist是讓每一個worker進程執行屬於本身的測試用例集下的全部測試用例oop

這意味着在不一樣進程中,不一樣的測試用例可能會調用同一個scope範圍級別較高(例如session)的fixture,該fixture則會被執行屢次,這不符合scope=session的預期測試

 

如何解決?

雖然pytest-xdist沒有內置的支持來確保會話範圍的夾具僅執行一次,可是能夠經過使用鎖定文件進行進程間通訊來實現。

 

小栗子

  1. 下面的示例只須要執行一次login(由於它是隻須要執行一次來定義配置選項,等等)
  2. 當第一次請求這個fixture時,則會利用FileLock僅產生一次fixture數據
  3. 當其餘進程再次請求這個fixture時,則會從文件中讀取數據
import pytest
from filelock import FileLock


@pytest.fixture(scope="session")
def login():
    print("====登陸功能,返回帳號,token===")
    with FileLock("session.lock"):
        name = "testyy"
        token = "npoi213bn4"
        # web ui自動化
        # 聲明一個driver,再返回

        # 接口自動化
        # 發起一個登陸請求,將token返回均可以這樣寫

    yield name, token
    print("====退出登陸!!!====")
相關文章
相關標籤/搜索