Pytest08-pytest工具與插件

8.pytest工具與插件

8.1 converage.py-代碼覆蓋率

? ? 測試覆蓋率是指項目代碼被測試用例覆蓋的百分比。使用覆蓋率工具可以知道,系統哪些部分的功能沒有被測試覆蓋。converage.py是Python推薦的覆蓋率工具。

8.1.1 覆蓋率工具安裝

? ? 在pytest中可以使用pytest-cov插件,其安裝方法如下所示:

pip install -U pytest-cov

8.1.2 常用用法

1.運行pytest-cov

? ? 使用覆蓋工具,可使用選項--cov=src,示例代碼路徑如下所示:

Lesson05
  |——src
  |    |—— sample
  |    |——————| __init__.py
  |    |——————| calculator.py
  |    |——————| ListSample.py
  |——test
  |    |——————| __init__.py
  |    |——————| conftest.py
  |    |——————| test_calculator.py

? ? 各代碼詳細內容如下所示:

calculator.py

def calculator(x,y,operator):
    if not isinstance(x,(int,)) or not isinstance(y,(int,)) or not isinstance(operator,(str,)):
        raise TypeError("args must be integer")
    elif operator=="+":
        return x+y
    elif operator=="-":
        return x-y
    elif operator=="*":
        return x*y
    elif operator=="/" and y!=0:
        return x/y
    else:
        raise ValueError("operator must be + - * /")

ListSample.py

tmpList = []
def registor(name,pwd):
    if name or pwd:
       raise ValueError("name or password is empty")
    else:
        tmpList.append({"name":name,"password":pwd})

def getUserInfo(name):
    if name:
        raise ValueError("name is empty")
    else:
        for item in tmpList:
            if name in item.values():
                return item

conftest.py

@pytest.fixture(name="addFixture")
def getAddData():
    return [(1, 2, 3), (4, 5, 9), (-9, -8, -17)]

@pytest.fixture(name="subFixture")
def getSubData():
    return [(1, 2, -1), (4, 5, -1), (-9, -8, -1)]

@pytest.fixture(name="registorData")
def getRegistorData():
    return [("Surpass","1"),("Surmount","2")]

test_calculator.py

import sys
import os
sys.path.append((os.path.abspath(os.path.join(os.path.dirname(__file__),"../src/sample"))))
from calculator import calculator

def test_add(addFixture):
    for item in addFixture:
        actual=calculator(item[0],item[1],"+")
        expect=item[2]
        assert actual==expect

def test_sub(subFixture):
    for item in subFixture:
        actual=calculator(item[0],item[1],"-")
        expect=item[2]
        assert actual==expect

? ? 運行覆蓋率工具結果如下所示:

>>> Lesson05> pytest --cov=src
================================ test session starts =========================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson05
plugins: cov-2.9.0
collected 2 items

test\test_calculator.py ..                                             [100%]

----------- coverage: platform win32, python 3.7.6-final-0 -----------
Name                       Stmts   Miss  Cover
----------------------------------------------
src\sample\ListSample.py      11     11     0%
src\sample\__init__.py         0      0   100%
src\sample\calculator.py      12      6    50%
----------------------------------------------
TOTAL                         23     17    26%

============================ 2 passed in 0.21s =================================

? ? 使用--cov=src指定源碼所在路徑,可以單獨計算此目錄的覆蓋率并生成報告。從生成的報告中,可以看到各個代碼相應的
覆蓋率。如果需要查看遺漏的哪些代碼,可以生成HTML報告。

2.生成HTML報告

? ? 如果要生成HTML報告,可以使用選項--cov-report=html,如下所示:

>>> Lesson05>pytest --cov=src --cov-report=html
==========================test session starts =============================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson05
plugins: cov-2.9.0
collected 2 items

test\test_calculator.py ..                                         [100%]

----------- coverage: platform win32, python 3.7.6-final-0 -----------
Coverage HTML written to dir htmlcov

=========================== 2 passed in 0.26s ============================

? ? 運行完成,會在根目錄(本例為Lesson05)中生成一個htmlcov文件夾,進入文件夾后,使用瀏覽器打開index.html文件,點擊對應的文件,即可打與之對應的測試詳細報告,如下所示:

080102覆蓋率報告.png
  • 從詳情頁面中可以看到已經覆蓋的和未覆蓋的數量
  • 底色為紅色的代表未覆蓋的代碼,如乘法、除法和參數x,y不是整形,operator不是字符串等

8.2 重復運行測試

? ? 如果希望一個會話中重復運行測試,則可以使用pytest-repeat。安裝方式如下所示:

pip install -U pytest-repeat

? ? 安裝完成pytest-repeat之后,可以使用--count來指定每個測試用例運行的次數,如下所示:

>>> Lesson05>pytest --count=5 -v .
=====================test session starts ================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson05
plugins: cov-2.9.0, repeat-0.8.0
collected 10 items

test/test_calculator.py::test_add[1-5] PASSED                          [ 10%]
test/test_calculator.py::test_add[2-5] PASSED                          [ 20%]
test/test_calculator.py::test_add[3-5] PASSED                          [ 30%]
test/test_calculator.py::test_add[4-5] PASSED                          [ 40%]
test/test_calculator.py::test_add[5-5] PASSED                          [ 50%]
test/test_calculator.py::test_sub[1-5] PASSED                          [ 60%]
test/test_calculator.py::test_sub[2-5] PASSED                          [ 70%]
test/test_calculator.py::test_sub[3-5] PASSED                          [ 80%]
test/test_calculator.py::test_sub[4-5] PASSED                          [ 90%]
test/test_calculator.py::test_sub[5-5] PASSED                          [100%]

========================= 10 passed in 0.19s =================================

8.3 并行運行測試

? ? 通常測試都是依次順序執行的。如果各個測試用例之前沒有需要共享使用的資料、配置、數據等,則可以考慮并行運行,從而提高效率。并行運行測試可以使用pytest-xdist,安裝方式如下所示:

pip install -U pytest-xdist

? ? 我們來測試使用pytest-xdist是否真能提高效率。

import pytest
import time
@pytest.mark.parametrize("x",range(10))
def test_paraell(x):
    time.sleep(1)

? ? 運行結果如下所示:

>>>p ytest -v test_paraell.py
=======================test session starts ======================================
latform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
achedir: .pytest_cache
ootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson06
lugins: cov-2.9.0, repeat-0.8.0
ollected 10 items

est_paraell.py::test_paraell[0] PASSED                                   [ 10%]
est_paraell.py::test_paraell[1] PASSED                                   [ 20%]
est_paraell.py::test_paraell[2] PASSED                                   [ 30%]
est_paraell.py::test_paraell[3] PASSED                                   [ 40%]
est_paraell.py::test_paraell[4] PASSED                                   [ 50%]
est_paraell.py::test_paraell[5] PASSED                                   [ 60%]
est_paraell.py::test_paraell[6] PASSED                                   [ 70%]
est_paraell.py::test_paraell[7] PASSED                                   [ 80%]
est_paraell.py::test_paraell[8] PASSED                                   [ 90%]
est_paraell.py::test_paraell[9] PASSED                                   [100%]

========================10 passed in 10.27s ====================================

? ? 使用pytest-xdist后,運行結果如下所示:

>>> pytest -v -n auto .\test_paraell.py
======================test session starts ==============================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson06
plugins: cov-2.9.0, forked-1.1.3, repeat-0.8.0, xdist-1.32.0
[gw0] win32 Python 3.7.6 cwd: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson06
[gw1] win32 Python 3.7.6 cwd: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson06
[gw2] win32 Python 3.7.6 cwd: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson06
[gw3] win32 Python 3.7.6 cwd: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson06
[gw0] Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)]
[gw1] Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)]
[gw2] Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)]
[gw3] Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)]
gw0 [10] / gw1 [10] / gw2 [10] / gw3 [10]
scheduling tests via LoadScheduling

test_paraell.py::test_paraell[1]
test_paraell.py::test_paraell[0]
test_paraell.py::test_paraell[2]
test_paraell.py::test_paraell[3]
[gw0] [ 10%] PASSED test_paraell.py::test_paraell[0]
[gw2] [ 20%] PASSED test_paraell.py::test_paraell[2]
[gw3] [ 30%] PASSED test_paraell.py::test_paraell[3]
[gw1] [ 40%] PASSED test_paraell.py::test_paraell[1]
test_paraell.py::test_paraell[4]
test_paraell.py::test_paraell[6]
test_paraell.py::test_paraell[7]
test_paraell.py::test_paraell[5]
[gw0] [ 50%] PASSED test_paraell.py::test_paraell[4]
[gw3] [ 60%] PASSED test_paraell.py::test_paraell[7]
[gw2] [ 70%] PASSED test_paraell.py::test_paraell[6]
[gw1] [ 80%] PASSED test_paraell.py::test_paraell[5]
test_paraell.py::test_paraell[8]
test_paraell.py::test_paraell[9]
[gw0] [ 90%] PASSED test_paraell.py::test_paraell[8]
[gw2] [100%] PASSED test_paraell.py::test_paraell[9]

=========================== 10 passed in 5.37s ===============================

? ? pytest-xdist使用參數-n=processornum或auto,可以指定運行測試的處理器進程數,如果為auto,則可以自動檢測系統CPU數目。

8.4 設置超時時間

? ? 正常情況下,pytest中的測試是沒有時間限制的。但如果想對一些測試設置時間限制,則可以使用pytest-timeout該插件可以在命令行指定超時時間或直接在測試代碼中標注超時時間,其安裝方式如下所示:

pip install -U pytest-timeout

測試用例上標注的超時時間優先級高于命令行上的超時時間,所以測試時間可能長于或短于命令行的設置

>>> pytest --timeout=0.5 -x .\test_paraell.py
========================= test session starts ============================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson06
plugins: cov-2.9.0, forked-1.1.3, repeat-0.8.0, timeout-1.3.4, xdist-1.32.0
timeout: 0.5s
timeout method: thread
timeout func_only: False
collected 10 items

test_paraell.py
+++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++

~~~~~~~~~~~~~~~~~~~~ Stack of MainThread (10272) ~~~~~~~~~~~~~~~~~~~~~~~~~~~

  File "d:\program files\python\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "d:\program files\python\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "D:\Program Files\Python\Scripts\pytest.exe\__main__.py", line 7, in <module>
    sys.exit(main())
  File "d:\program files\python\lib\site-packages\_pytest\config\__init__.py", line 125, in main
  ...
    time.sleep(1)

++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++++

8.5 查看詳細錯誤信息

? ? 通常pytest會顯示每個測試的運行狀態,當的有測試運行完畢后,pytest將顯示錯誤和失敗用例的錯誤信息。如果測試很快就運行完成,可能不是問題。但如果運行需要很長時間,就希望一出錯就能看到錯誤信息。針對這種情況,可以使用pytest-instafail,安裝方式如下所示:

pip install -U pytest-instafail

? ? 使用pytest-instafail后的情況,如下所示:

>>>  pytest --instafail --timeout=0.5 --tb=line --maxfa=2 .\test_paraell.py
================= test session starts =====================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson06
plugins: cov-2.9.0, forked-1.1.3, instafail-0.4.1.post0, repeat-0.8.0, timeout-1.3.4, xdist-1.32.0
timeout: 0.5s
timeout method: thread
timeout func_only: False
collected 10 items

test_paraell.py
+++++++++++++++++++++++++++++++Timeout +++++++++++++++++++++++++++++++++++++

~~~~~~~~~~~~~~~~~~~~~~~ Stack of MainThread (8316) ~~~~~~~~~~~~~~~~~~~~~~~~~~

  File "d:\program files\python\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "d:\program files\python\lib\runpy.py", line 85, in _run_code
  ..
++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++++

8.6 顯示色彩和進度條

? ? 默認的pytest運行時,是沒有進度條和色彩的,如果想要美化一些,可以使用pytest-sugar添加一些色彩和進度條,其安裝方式如下所示:

pip install -U pytest-sugar

? ? 使用方式如下所示:

080601顯示進度條的色彩.png

8.7 生成HTML報告

? ? 為pytest生成一份HTML報告,可以直觀的查看各測試用例運行情況,可以使用pytest-html,其安裝方式如下所示:

pip install -U pytest-html

? ? 用法如下所示:

pytest -v --html=report.html .

? ? 運行完成后,會在指定的目錄生成一份HTML格式的報告,內容包含通過、跳過、失敗、錯誤、預期失敗和預測失敗但實際通過的詳細信息,如下所示:

080701生成HTM報告.png

? ? 默認生成報告是包含css文件和html文件,兩者只有在同一個目錄時,才能查看完整的測試報告,如果需要生成一份獨立的HTML報告,可以使用參數--html=report.html --self-contained-html,使用方式如下所示:

pytest -v --html=D:\report.html --self-contained-html
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,296評論 2 376