日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python开源考试_可能是 Python 中最火的第三方开源测试框架 pytest

發布時間:2023/12/20 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python开源考试_可能是 Python 中最火的第三方开源测试框架 pytest 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:HelloGitHub-Prodesire

一、介紹

本篇文章是《聊聊 Python 的單元測試框架》的第三篇,前兩篇分別介紹了標準庫 unittest 和第三方單元測試框架 nose。作為本系列的最后一篇,壓軸出場的是Python 世界中最火的第三方單元測試框架:pytest。

它有如下主要特性:

assert 斷言失敗時輸出詳細信息(再也不用去記憶 self.assert* 名稱了)

自動發現 測試模塊和函數

模塊化夾具 用以管理各類測試資源

對 unittest 完全兼容,對 nose 基本兼容

非常豐富的插件體系,有超過 315 款第三方插件,社區繁榮

和前面介紹 unittest 和 nose 一樣,我們將從如下幾個方面介紹 pytest 的特性。

二、用例編寫

同 nose 一樣,pytest 支持函數、測試類形式的測試用例。最大的不同點是,你可以盡情地使用 assert 語句進行斷言,絲毫不用擔心它會在 nose 或 unittest 中產生的缺失詳細上下文信息的問題。

比如下面的測試示例中,故意使得 test_upper 中斷言不通過:

import pytest

def test_upper():

assert 'foo'.upper() == 'FOO1'

class TestClass:

def test_one(self):

x = "this"

assert "h" in x

def test_two(self):

x = "hello"

with pytest.raises(TypeError):

x + []

而當使用 pytest 去執行用例時,它會輸出詳細的(且是多種顏色)上下文信息:

=================================== test session starts ===================================

platform darwin -- Python 3.7.1, pytest-4.0.1, py-1.7.0, pluggy-0.8.0

rootdir: /Users/prodesire/projects/tests, inifile:

plugins: cov-2.6.0

collected 3 items

test.py F.. [100%]

======================================== FAILURES =========================================

_______________________________________ test_upper ________________________________________

def test_upper():

> assert 'foo'.upper() == 'FOO1'

E AssertionError: assert 'FOO' == 'FOO1'

E - FOO

E + FOO1

E ? +

test.py:4: AssertionError

=========================== 1 failed, 2 passed in 0.08 seconds ============================

不難看到,pytest 既輸出了測試代碼上下文,也輸出了被測變量值的信息。相比于 nose 和 unittest,pytest 允許用戶使用更簡單的方式編寫測試用例,又能得到一個更豐富和友好的測試結果。

三、用例發現和執行

unittest 和 nose 所支持的用例發現和執行能力,pytest 均支持。

pytest 支持用例自動(遞歸)發現:

默認發現當前目錄下所有符合 test_*.py 或 *_test.py 的測試用例文件中,以 test 開頭的測試函數或以 Test 開頭的測試類中的以 test 開頭的測試方法

使用 pytest 命令

同 nose2 的理念一樣,通過在配置文件中指定特定參數,可配置用例文件、類和函數的名稱模式(模糊匹配)

pytest 也支持執行指定用例:

指定測試文件路徑

pytest /path/to/test/file.py

指定測試類

pytest /path/to/test/file.py:TestCase

指定測試方法

pytest another.test::TestClass::test_method

指定測試函數

pytest /path/to/test/file.py:test_function

四、測試夾具(Fixtures)

pytest 的測試夾具和 unittest、nose、nose2的風格迥異,它不但能實現 setUp 和 tearDown這種測試前置和清理邏輯,還其他非常多強大的功能。

4.1 聲明和使用

pytest 中的測試夾具更像是測試資源,你只需定義一個夾具,然后就可以在用例中直接使用它。得益于 pytest 的依賴注入機制,你無需通過from xx import xx的形式顯示導入,只需要在測試函數的參數中指定同名參數即可,比如:

import pytest

@pytest.fixture

def smtp_connection():

import smtplib

return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)

def test_ehlo(smtp_connection):

response, msg = smtp_connection.ehlo()

assert response == 250

上述示例中定義了一個測試夾具 smtp_connection,在測試函數 test_ehlo 簽名中定義了同名參數,則 pytest 框架會自動注入該變量。

4.2 共享

在 pytest 中,同一個測試夾具可被多個測試文件中的多個測試用例共享。只需在包(Package)中定義 conftest.py 文件,并把測試夾具的定義寫在該文件中,則該包內所有模塊(Module)的所有測試用例均可使用 conftest.py 中所定義的測試夾具。

比如,如果在如下文件結構的 test_1/conftest.py 定義了測試夾具,那么 test_a.py 和 test_b.py 可以使用該測試夾具;而 test_c.py 則無法使用。

`-- test_1

| |-- conftest.py

| `-- test_a.py

| `-- test_b.py

`-- test_2

`-- test_c.py

4.3 生效級別

unittest 和 nose 均支持測試前置和清理的生效級別:測試方法、測試類和測試模塊。

pytest 的測試夾具同樣支持各類生效級別,且更加豐富。通過在 pytest.fixture 中指定 scope 參數來設置:

function —— 函數級,即調用每個測試函數前,均會重新生成 fixture

class —— 類級,調用每個測試類前,均會重新生成 fixture

module —— 模塊級,載入每個測試模塊前,均會重新生成 fixture

package —— 包級,載入每個包前,均會重新生成 fixture

session —— 會話級,運行所有用例前,只生成一次 fixture

當我們指定生效級別為模塊級時,示例如下:

import pytest

import smtplib

@pytest.fixture(scope="module")

def smtp_connection():

return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)

4.4 測試前置和清理

pytest 的測試夾具也能夠實現測試前置和清理,通過 yield 語句來拆分這兩個邏輯,寫法變得很簡單,如:

import smtplib

import pytest

@pytest.fixture(scope="module")

def smtp_connection():

smtp_connection = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)

yield smtp_connection # provide the fixture value

print("teardown smtp")

smtp_connection.close()

在上述示例中,yield smtp_connection 及前面的語句相當于測試前置,通過 yield 返回準備好的測試資源 smtp_connection;

而后面的語句則會在用例執行結束(確切的說是測試夾具的生效級別的聲明周期結束時)后執行,相當于測試清理。

如果生成測試資源(如示例中的 smtp_connection)的過程支持 with 語句,那么還可以寫成更加簡單的形式:

@pytest.fixture(scope="module")

def smtp_connection():

with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp_connection:

yield smtp_connection # provide the fixture value

五、跳過測試和預計失敗

pytest 除了支持 unittest 和 nosetest 的跳過測試和預計失敗的方式外,還在 pytest.mark 中提供對應方法:

通過 skipif按條件跳過測試

通過 xfail 預計測試失敗

示例如下:

@pytest.mark.skip(reason="no way of currently testing this")

def test_mark_skip():

...

def test_skip():

if not valid_config():

pytest.skip("unsupported configuration")

@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6 or higher")

def test_mark_skip_if():

...

@pytest.mark.xfail

def test_mark_xfail():

...

六、子測試/參數化測試

pytest 除了支持 unittest 中的 TestCase.subTest,還支持一種更為靈活的子測試編寫方式,也就是 參數化測試,通過 pytest.mark.parametrize 裝飾器實現。

在下面的示例中,定義一個 test_eval 測試函數,通過 pytest.mark.parametrize 裝飾器指定 3 組參數,則將生成 3 個子測試:

@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])

def test_eval(test_input, expected):

assert eval(test_input) == expected

示例中故意讓最后一組參數導致失敗,運行用例可以看到豐富的測試結果輸出:

========================================= test session starts =========================================

platform darwin -- Python 3.7.1, pytest-4.0.1, py-1.7.0, pluggy-0.8.0

rootdir: /Users/prodesire/projects/tests, inifile:

plugins: cov-2.6.0

collected 3 items

test.py ..F [100%]

============================================== FAILURES ===============================================

__________________________________________ test_eval[6*9-42] __________________________________________

test_input = '6*9', expected = 42

@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])

def test_eval(test_input, expected):

> assert eval(test_input) == expected

E AssertionError: assert 54 == 42

E + where 54 = eval('6*9')

test.py:6: AssertionError

================================= 1 failed, 2 passed in 0.09 seconds ==================================

若將參數換成 pytest.param,我們還可以有更高階的玩法,比如知道最后一組參數是失敗的,所以將它標記為 xfail:

@pytest.mark.parametrize(

"test_input,expected",

[("3+5", 8), ("2+4", 6), pytest.param("6*9", 42, marks=pytest.mark.xfail)],

)

def test_eval(test_input, expected):

assert eval(test_input) == expected

如果測試函數的多個參數的值希望互相排列組合,我們可以這么寫:

@pytest.mark.parametrize("x", [0, 1])

@pytest.mark.parametrize("y", [2, 3])

def test_foo(x, y):

pass

上述示例中會分別把 x=0/y=2、x=1/y=2、x=0/y=3和x=1/y=3帶入測試函數,視作四個測試用例來執行。

七、測試結果輸出

pytest 的測試結果輸出相比于 unittest 和 nose 來說更為豐富,其優勢在于:

高亮輸出,通過或不通過會用不同的顏色進行區分

更豐富的上下文信息,自動輸出代碼上下文和變量信息

測試進度展示

測試結果輸出布局更加友好易讀

八、插件體系

pytest 的插件十分豐富,而且即插即用,作為使用者不需要編寫額外代碼。關于插件的使用,參見"Installing and Using plugins"。

此外,得益于 pytest 良好的架構設計和鉤子機制,其插件編寫也變得容易上手。關于插件的編寫,參見"Writing plugins"。

九、總結

三篇關于 Python 測試框架的介紹到這里就要收尾了。寫了這么多,各位看官怕也是看得累了。我們不妨羅列一個橫向對比表,來總結下這些單元測試框架的異同:

unittest

nose

nose2

pytest

自動發現用例

?

?

?

?

指定(各級別)用例執行

?

?

?

?

支持 assert 斷言

測試夾具

?

?

?

?

測試夾具種類

前置和清理

前置和清理

前置和清理

前置、清理、內置各類 fixtures,自定義各類 fixtures

測試夾具生效級別

方法、類、模塊

方法、類、模塊

方法、類、模塊

方法、類、模塊、包、會話

支持跳過測試和預計失敗

?

?

?

?

子測試

?

?

?

?

測試結果輸出

一般

較好

較好

插件

-

較豐富

一般

豐富

鉤子

-

-

?

?

社區生態

作為標準庫,由官方維護

停止維護

維護中,活躍度低

維護中,活躍度高

Python 的單元測試框架看似種類繁多,實則是一代代的進化,有跡可循。抓住其特點,結合使用場景,就能容易的做出選擇。

若你不想安裝或不允許第三方庫,那么 unittest 是最好也是唯一的選擇。反之,pytest 無疑是最佳選擇,眾多 Python 開源項目(如大名鼎鼎的 requests)都是使用 pytest 作為單元測試框架。甚至,連 nose2 在官方文檔上都建議大家使用 pytest,這得是多大的敬佩呀!

『講解開源項目系列』——讓對開源項目感興趣的人不再畏懼、讓開源項目的發起者不再孤單。跟著我們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎留言聯系我們、加入我們,讓更多人愛上開源、貢獻開源~

總結

以上是生活随笔為你收集整理的python开源考试_可能是 Python 中最火的第三方开源测试框架 pytest的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。