pytest入門基礎

參考學習官網文檔:https://docs.pytest.org/en/latest/getting-started.html

一、pytest簡介

1. 前言:測試框架與測試工具

  • 測試框架、測試工具這兩個概念經常容易搞混了,測試框架是諸如 Unittest、Pytest、TestNG 這類,而測試工具指的則是 Selenium、Appium、Jmeter 這類。
  • 測試框架的作用是,幫助管理測試用例、執(zhí)行測試用例、參數(shù)化、斷言、生成測試報告等基礎性工作,讓我們將精力用在測試用例的編寫上。好的測試框架應該具有很高的擴展性,支持二次開發(fā),并能夠支持多種類型的自動化測試。
  • 測試工具的作用是為了完成某一類型的測試,比如 Selenium 用于對 WEB UI 進行自動化測試,Appium 用來對 APP 進行自動化測試,Jmeter 可以用來進行 API 自動化測試和性能測試。另外,Java 語言中 OkHttp 庫,Python 語言中的 requests 庫,這些 HTTP 的 client 也可以看做是一種 API 測試工具。

2. 單元測試框架

  • 1)什么是單元測試框架?
    單元測試是指軟件開發(fā)中,針對軟件的最小單位(函數(shù)、方法)進行正確性的檢查測試,Java:junit、testing
    Python:unittest、pytest
  • 2)單元測試框架主要做什么?
    ① 測試發(fā)現(xiàn):從多個文件里面去找我們得測試用例
    ② 測試執(zhí)行:按照一定的順序和規(guī)則去執(zhí)行,并生成結果
    ③ 測試判斷:通過斷言判斷預期結果和實際結果的差異
    ④ 測試報告:統(tǒng)計測試進度、耗時、通過率、生成測試報告

3. pytest簡介

  • Pytest 是 Python 的一種易用、高效和靈活的單元測試框架,可以支持單元測試和功能測試
  • pytest可以和selenium,requests,appium結合實現(xiàn)web自動化、接口自動化、app自動化
  • pytest可以實現(xiàn)測試用例的跳過以及reruns(失敗用例重試)
  • pytest可以和allure生成非常美觀的測試報告
  • pytest可以和jenkins持續(xù)集成
  • pytest有很多非常強大的插件,并且這些插件能夠實現(xiàn)很多實用的操作
    ① pytest-xdist:測試用例分布式執(zhí)行,多cpu分發(fā)
    ② pytest-ordering:用于改變測試用例的執(zhí)行順序
    ③ pytest-rerunfailures:用例失敗后重跑
    ④ pytest-html:生成html格式的自動化測試報告
    ⑤ allure-pytest:用于生成美觀測試報告


二、安裝pytest

pytest需要:Python 3.7+ 或 PyPy3

  1. 在命令行中運行以下命令
pip install -U pytest

其他插件安裝方法也是一樣pip安裝

  1. 檢查是否安裝成功
    pytest


三、pytest使用規(guī)則

  1. 模塊名必須以test_開頭或test_結尾
  2. 測試類必須以Test開頭,且不能有init方法
  3. 測試方法必須以test開頭
    使用規(guī)則


四、測試用例執(zhí)行

pytest 用例的執(zhí)行主要有以下三種方式:

  • 通過命令模式執(zhí)行
  • 通過主函數(shù)執(zhí)行
  • 通過讀取 pytest.ini 配置文件執(zhí)行

4.1 通過命令模式執(zhí)行

測試文件test_demo.py:Pytest 使用 Python 的 assert 進行條件判斷,簡單的測試函數(shù)如:

def test_product_case001():
    print("模擬測試模塊1的功能")
    assert 1 + 1 == 3


def test_product_case002():
    print("模擬測試模塊2的功能")
    assert 1 == 1
1)執(zhí)行所有用例

pytest 命令執(zhí)行當前目錄下所有的測試用例,所以要想執(zhí)行項目中所有的用例,只需要將執(zhí)行目錄切換到根目錄即可:

image.png

可以加上-v參數(shù)查看詳情pytest -v

image.png

2)指定執(zhí)行

執(zhí)行指定目錄:
執(zhí)行指定目錄

執(zhí)行指定文件:
執(zhí)行指定文件

執(zhí)行指定用例:
執(zhí)行指定用例


4.2 通過主函數(shù)執(zhí)行

1)主函數(shù)運行

test_demo.py添加主函數(shù):

import pytest

class Testdemo:
    def test_case_passed(self):
        print("模擬執(zhí)行成功場景的case")
        assert (1, 2, 3) == (1, 2, 3)

def test_case_failed():
    print("模擬執(zhí)行失敗場景的case")
    assert 3 == 1 + 1

if __name__ == '__main__':
    pytest.main(["-v"])    # 執(zhí)行測試用例,-v參數(shù)打印詳細信息

然后直接運行:
執(zhí)行結果

從終端的打印可以看到,用例文件中的用例方法 test_case_failed 以及測試類中的測試方法 test_case_passed 都被執(zhí)行了。

2)批量執(zhí)行

只需要在對應的用例文件中調用主函數(shù),就可以自動執(zhí)行文件中的所有用例。
但是在實際的使用中,一般會將用例分類寫在不同目錄下的不同用例文件里,且執(zhí)行時要批量去執(zhí)行所有的用例,所以往往會將主函數(shù)寫在一個與用例文件夾平級的 py 文件中,pytest 內部設有對應的機制,會自動掃描全局,執(zhí)行所有的用例文件。

主函數(shù)文件所在目錄:
主函數(shù)文件

運行主函數(shù)文件main.py,輸出結果可以看到所有用例均被執(zhí)行了:

批量執(zhí)行

3)指定執(zhí)行

pytest.main()可以加上命令參數(shù)運行,如下

指定目錄
指定目錄

指定文件
指定文件

指定用例
指定用例


4.3 通過 pytest.ini 配置文件執(zhí)行

在項目中,通常通過配置全局的配置文件來執(zhí)行測試用例的。其余兩種執(zhí)行方式在編寫和調試用例時比較方便。對于配置文件,有以下幾點要求:

  • 配置文件的名字必須為 pytest.ini
  • 配置文件一般放置在項目的根目錄
  • 配置文件必須時 ANSI 編碼
  • 配置了pytest.ini文件后,不管是主函數(shù)模式運行用例,還是命令行模式運行用例,都會去讀取pytest.ini配置文件中的內容。
  • CMD命令行中執(zhí)行pytest -h命令,可以查看pytest.ini的設置選項。

pytest.ini 是 pytest 框架的核心配置文件,它可以改變 pytest 的默認行為,不管是通過主函數(shù)還是命令模式去執(zhí)行用例,都會先去讀取配置文件。

修改完配置文件,再去執(zhí)行用例時就會按照配置文件的要求去執(zhí)行:
配置文件


五、執(zhí)行參數(shù)

我們在執(zhí)行用例時,可以通過添加相關的參數(shù)實現(xiàn)不同的執(zhí)行效果,提升測試效率。

1)-s:用于輸出調試信息,包括打印輸出的信息

# 通過main函數(shù)執(zhí)行
pytest.main(["-s", "./product_cases/test_product.py"])
# 通過命令模式執(zhí)行
pytest -s ./product_cases/test_product.py
-s

2)-v:顯示更詳細的信息

# 通過main函數(shù)執(zhí)行
pytest.main(["-v", "./product_cases/test_product.py"])
# 通過命令模式執(zhí)行
pytest -v ./product_cases/test_product.py
-v

3)-vs:將 -v 和 -s 參數(shù)效果結合,推薦使用
-vs

4)-n:支持多線程或者分布式運行測試用例

n是進程數(shù),也就是cpu個數(shù),最大值為當前機器cpu個數(shù),也可以設置為auto,自動識別cpu個數(shù)。

# 通過main函數(shù)執(zhí)行
# 開兩個線程去執(zhí)行用戶操作目錄下所有的用例
pytest.main(["-vs", "./product_cases", "-n=2"])

# 通過命令模式執(zhí)行
pytest -vs ./product_cases -n 2

為了方便看出測試效果,給test_product.py文件中的每個測試用例都增加sleep(2)

import pytest,time


def test_product_case001():
    time.sleep(2)
    print("模擬測試模塊1的功能")
    assert 1 + 1 == 2


def test_product_case002():
    time.sleep(2)
    print("模擬測試模塊2的功能")
    assert 1 == 1

正常執(zhí)行結果:用時4.05s
單線程執(zhí)行

開啟2個線程執(zhí)行結果:用時2.60s
多線程執(zhí)行

5)--reruns:失敗用例重跑

# 通過main函數(shù)執(zhí)行
# 如果用例執(zhí)行失敗,該用例再執(zhí)行2次
pytest.main(["-vs", "./product_cases", "--reruns=2"])

# 通過命令模式執(zhí)行
pytest -vs ./product_cases --reruns 2

修改test_product.py文件

def test_product_case001():
    print("模擬測試模塊1的功能")
    assert 1 + 1 == 3


def test_product_case002():
    print("模擬測試模塊2的功能")
    assert 1 == 1
失敗重跑

6)-x:只要有一個用例失敗,就停止執(zhí)行

# 通過main函數(shù)執(zhí)行
pytest.main(["-vs", "./product_cases", "-x"])

# 通過命令模式執(zhí)行
pytest -vs ./product_cases -x

test_product_case001失敗,停止執(zhí)行,test_product_case002未執(zhí)行

失敗停止執(zhí)行g

7)--maxfail:失敗的用例數(shù)達到規(guī)定值時停止測試

# 失敗的用例數(shù)達到2個時停止測試
# 通過main函數(shù)執(zhí)行
pytest.main(["-vs", "./product_cases", "--maxfail=2"])

# 通過命令模式執(zhí)行
pytest -vs ./product_cases --maxfail 2
失敗停止測試

8)-k:關鍵字過濾執(zhí)行

-k會匹配文件名、類名、方法名匹配表達式的用例,如果指定的表達式是被文件名/測試類名包含的,那么文件/測試類中所有的測試方法都會被執(zhí)行。

# 執(zhí)行文件名/類名/方法名中包含01的用例
# 通過main函數(shù)執(zhí)行
pytest.main(["-vs", "./product_cases", "-k=01"])

# 通過命令模式執(zhí)行
pytest -vs ./product_cases -k="01"

指定執(zhí)行測試用例名稱包含01

過濾執(zhí)行

指定執(zhí)行測試用例名稱包含login

過濾執(zhí)行

9)--html:用例執(zhí)行完成后生成 html 格式的測試報告

pytest -vs --html ./report/result.html --html+報告存放路徑參數(shù)

生成html報告

result.html


六、用例執(zhí)行順序

修改 test_product.py 中測試方法:

def test_product_case():
    print("模擬測試產品相關的操作")

def test_case_001():
    print("測試方法_001")

def test_case_002():
    print("測試方法_002")

def test_case_003():
    print("測試方法_003")

def test_case_004():
    print("測試方法_004")

def test_case_005():
    print("測試方法_005")

1)默認執(zhí)行順序

pytest 對于用例的執(zhí)行順序是按照從上到下執(zhí)行的

從上往下執(zhí)行

2) 改變用例的執(zhí)行順序

通過裝飾器方法@pytest.mark.run()可以改變用例的執(zhí)行順序,參數(shù)order=n指定排在第n個執(zhí)行

# product_cases/test_product.py
import pytest

def test_product_case():
    print("模擬測試產品相關的操作")

# 通過裝飾器方法 @pytest.mark.run() 可以改變用例的執(zhí)行順序
# order參數(shù)表示該用例要排在第幾個執(zhí)行
@pytest.mark.run(order=1)
def test_case_002():
    print("測試方法_002")

@pytest.mark.run(order=2)
def test_case_003():
    print("測試方法_003")

def test_case_004():
    print("測試方法_004")

def test_case_005():
    print("測試方法_005")
指定執(zhí)行順序

從終端輸出的結果可以看到,被裝飾器裝飾的測試用例都按照了指定的順序執(zhí)行,沒有被裝飾到的用例還是按照從上到下的順序執(zhí)行


七、標記函數(shù),分組執(zhí)行用例

1)裝飾器@pytest.mark.name裝飾用例

第一步,使用裝飾器@pytest.mark.name去裝飾要執(zhí)行的用例,其中 name 為自定義的名稱

# product_cases/test_product.py
import pytest

# 通過裝飾器方法 @pytest.mark.finished標記已完成的用例
@pytest.mark.finished
def test_product_case():
    print("模擬測試產品相關的操作")

# 通過裝飾器方法 @pytest.mark.unfinished標記未完成功能的用例
@pytest.mark.unfinished
def test_case_002():
    print("測試方法_002")

@pytest.mark.unfinished
def test_case_003():
    print("測試方法_003")

def test_case_004():
    print("測試方法_004")

def test_case_005():
    print("測試方法_005")

2)pytest.ini 添加分組配置

第二步,去 pytest.ini 中添加分組配置,配置名必須和裝飾器中的 name 值一致
配置文件pytest.ini

3)參數(shù) -m 指定執(zhí)行用例

第三步,執(zhí)行時通過參數(shù) -m 指定要執(zhí)行的用例
執(zhí)行標記用例


八、跳過用例

對于某些不想執(zhí)行的用例,可以使用 pytest 提供的裝飾器方法@pytest.mark.skip()跳過該用例不去執(zhí)行

1)直接跳過

裝飾器語法:@pytest.mark.skip(reason="") ,reason 參數(shù)可選,表示跳過該測試方法的原因

@pytest.mark.skip

2)條件跳過

裝飾器語法:@pytest.mark.skipif(判斷條件, reason="") ,為測試函數(shù)指定被忽略的條件,reason 參數(shù)可選

# product_cases/test_product.py
import pytest

version = 1

# V2版本才支持,版本小于V2則跳過不執(zhí)行
@pytest.mark.skipif(version < 2, reason='not supported until v2')
def test_product_case():
    print("模擬測試產品相關的操作")

def test_case_001():
    print("測試方法_001")

def test_case_002():
    print("測試方法_002")
  • version=1滿足條件,跳過不執(zhí)行
    滿足條件跳過
  • version=2不滿足條件,不跳過執(zhí)行
    不滿足條件不跳過

文章轉載參考:http://www.chendacheng.com/content/?category=Pytest%E4%B8%93%E9%A2%98&article=Pytest_01.html

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容