Python測試框架-pytest與unittest的區(qū)別

前言

???????在Python中進行測試時,兩個最流行的測試框架是unittestpytest。雖然它們的目標相同,但它們之間存在許多不同之處波桩。
???????本文將詳細比較它們在用例編寫規(guī)則戒努、前置和后置方法、參數(shù)化镐躲、斷言功能储玫、用例執(zhí)行和報告生成等方面的差異,并適當補充pytest相較于unittest的其他優(yōu)點萤皂。

相同點

首先撒穷,讓我們看一下它們的共同點:
● 都是用于Python的測試框架
● 都使用斷言(assertions)來驗證代碼的正確性
● 都支持自動化測試

盡管它們有著相同的目標和基本特征,但在實際應用過程中表現(xiàn)出了不同的特點裆熙。

用例編寫規(guī)則的不同

unittest

???????在unittest中端礼,測試類必須繼承unittest.TestCase禽笑。測試方法必須以test_開頭,并且不能帶有參數(shù)蛤奥。以下是一個使用unittest編寫測試用例的示例:

import unittest

# 繼承 TestCase 類
class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])

        # 執(zhí)行測試
if __name__ == '__main__':
    unittest.main()

pytest

???????在pytest中佳镜,測試函數(shù)可以任意命名,無需繼承特定的基類或遵循特定的命名規(guī)范凡桥。以下是一個使用pytest編寫測試用例的示例:

# 測試函數(shù)可以隨意命名
def test_upper():
    assert 'foo'.upper() == 'FOO'

def test_isupper():
    assert 'FOO'.isupper()
    assert not 'Foo'.isupper()

def test_split():
    s = 'hello world'
    assert s.split() == ['hello', 'world']

這里不同之處在于pytest對測試用例命名和所繼承的基類沒有要求蟀伸,而unittest則需要遵循特定的命名規(guī)范和繼承特定的基類。

前置和后置方法的不同

unittest

???????unittest使用setUp和tearDown方法來設(shè)置和清理測試夾具(test fixtures)缅刽。setUp方法在每個測試方法之前執(zhí)行啊掏,用于準備測試環(huán)境; tearDown方法在每個測試方法之后執(zhí)行衰猛,用于清理測試環(huán)境迟蜜。以下是一個使用setUp和tearDown方法的示例:

import unittest

class TestStringMethods(unittest.TestCase):
    def setUp(self):
        self.text = 'hello world'

    def test_upper(self):
        self.assertEqual(self.text.upper(), 'HELLO WORLD')

    def tearDown(self):
        self.text = None

if __name__ == '__main__':
    unittest.main()

pytest

???????在pytest中,使用fixture系統(tǒng)管理測試夾具腕侄。夾具(fixture)是函數(shù)小泉、類或模塊級別的對象,可以提供測試數(shù)據(jù)冕杠、初始化代碼等微姊。如果需要在多個測試用例中重復使用相同的夾具,則fixture尤其有用分预。以下是一個使用fixture的示例:

import pytest

@pytest.fixture
def setup_text():
    return 'hello world'

def test_upper(setup_text):
    assert setup_text.upper() == 'HELLO WORLD'

這里不同之處在于pytest使用fixture來管理測試夾具兢交,而unittest則使用setUp和tearDown方法。

參數(shù)化的不同

unittest

???????在unittest中笼痹,參數(shù)化通常需要手動實現(xiàn)配喳。例如,使用for循環(huán)迭代測試數(shù)據(jù)凳干,并為每個數(shù)據(jù)集執(zhí)行一個測試方法:

import unittest

class TestMultiplication(unittest.TestCase):
    def test_numbers_3_4(self):
        self.assertEqual(3 * 4, 12)

    def test_numbers_2_4(self):
        self.assertEqual(2 * 4, 8)

        def test_numbers_6_9(self):
            self.assertEqual(6 * 9, 54)

pytest

???????pytest內(nèi)置支持參數(shù)化晴裹,使得為一組輸入執(zhí)行相同的測試變得非常容易。以下是一個使用@pytest.mark.parametrize裝飾器實現(xiàn)參數(shù)化測試的示例:

import pytest

# 參數(shù)化測試
@pytest.mark.parametrize("a, b, expected", [
    (3, 4, 12),
    (2, 4, 8),
    (6, 9, 54),
])
def test_multiplication(a, b, expected):
    assert a * b == expected

除此之外救赐,pytest還提供了更多靈活的參數(shù)化方式涧团,例如從CSV、YAML或JSON文件中加載測試數(shù)據(jù)等经磅。

斷言功能的不同

unittest

???????unittest只能使用assertEqual泌绣、assertTrue和assertFalse等基本斷言方法進行斷言。如果需要其他特殊類型的斷言预厌,則需要手動編寫代碼來實現(xiàn)阿迈。例如,如果需要比較兩個列表是否相等轧叽,則需要使用assertListEqual方法苗沧。

import unittest

class TestListMethods(unittest.TestCase):
    def test_list_equal(self):
        list1 = [1, 2, 3]
        list2 = [1, 2, 3]
        self.assertListEqual(list1, list2)

if __name__ == '__main__':
    unittest.main()

pytest

???????pytest具有更豐富的內(nèi)置斷言方法刊棕,例如assertAlmostEqual、assertDictEqual和assertRegex等崎页。如果需要自定義斷言鞠绰,則可以使用pytest.assert語法。

import pytest

def test_list_equal():
    list1 = [1, 2, 3]
    list2 = [1, 2, 3]
    assert list1 == list2

此外飒焦,pytest還支持自定義的assertion helper函數(shù)和插件來擴展斷言功能蜈膨。

用例執(zhí)行的不同

unittest

???????在unittest中,測試套件由TestLoader加載牺荠,并由TextTestRunner運行翁巍。以下是一個手動創(chuàng)建并運行測試套件的示例:

import unittest

class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestStringMethods('test_upper'))

    runner = unittest.TextTestRunner()
    runner.run(suite)

pytest

???????在pytest中,使用pytest命令行工具運行測試休雌。pytest會自動發(fā)現(xiàn)并執(zhí)行所有符合命名規(guī)則(test_*.py)的測試文件灶壶。以下是一個在終端中運行pytest測試的示例:

$ pytest

pytest還支持多種插件擴展測試功能,例如pytest-xdist可以實現(xiàn)分布式測試杈曲。以下是一個使用pytest-xdist插件進行并發(fā)執(zhí)行的示例:

$ pytest -n 4

這里不同之處在于unittest需要手動創(chuàng)建并運行測試套件驰凛,而pytest則由pytest命令行工具自動發(fā)現(xiàn)和執(zhí)行測試。

報告生成的不同

unittest

???????unittest默認情況下生成文本報告并將其輸出到控制臺担扑∏∠欤可以編寫一個單獨的測試運行器來生成HTML報告等其他格式。以下是一個使用HtmlTestRunner模塊創(chuàng)建HTML測試報告的示例:

import unittest
import HtmlTestRunner

class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

if __name__ == '__main__':
    unittest.main(testRunner=HtmlTestRunner.HTMLTestRunner(output='example_dir'))

pytest

???????在pytest中涌献,可以使用多個插件來生成各種格式的測試報告胚宦,例如pytest-html可以生成漂亮的HTML測試報告:

$ pytest --html=report.html

此外,還有更多插件支持生成JUnit XML燕垃、JSON和Allure等報告格式枢劝。

pytest其他優(yōu)點的補充

???????除了上述功能之外,pytest還提供了許多其他有用的特性卜壕,使得它比unittest更加靈活您旁、易用、高效和可擴展轴捎。以下是一些pytest的其他優(yōu)點:

參數(shù)化

???????pytest的參數(shù)化測試功能非常強大鹤盒,可以輕松地對一組輸入執(zhí)行相同的測試,并在測試失敗時提供更多的上下文信息轮蜕。參數(shù)化測試還可以與fixture系統(tǒng)一起使用昨悼,從而實現(xiàn)更高級的夾具設(shè)置蝗锥。例如跃洛,以下是一個使用參數(shù)化和fixture的示例:

import pytest

@pytest.fixture(params=[1, 2, 3])
def input_value(request):
    return request.param

def test_square(input_value):
    assert input_value ** 2 == 4

這里,fixture函數(shù)input_value返回一個參數(shù)(request.param) 终议,pytest將會用列表中的每個元素調(diào)用一次fixture汇竭。

fixture管理測試夾具

???????除了基本夾具之外葱蝗,pytest的fixture系統(tǒng)還支持諸如scope、autouse和yield-fixture等高級特性细燎。這使得夾具的管理變得更加容易和靈活两曼。例如,以下是一個使用autouse fixture自動啟用測試日志記錄的示例:

import pytest

@pytest.fixture(autouse=True)
def log_test_info(request):
    """Auto logs information about the tests being run"""
    print(f"Running test {request.node.name}")

這里玻驻,autouse=True表示此fixture將自動應用于所有測試用例悼凑,無需手動運行。

插件系統(tǒng)璧瞬,使得擴展功能變得非常容易

???????pytest的插件系統(tǒng)非常豐富户辫,支持大量第三方插件和自定義插件。這些插件可以輕松地擴展pytest的功能嗤锉,例如增強斷言渔欢、生成更高級別的報告、支持分布式測試等瘟忱。以下是一個使用pytest-html插件生成HTML測試報告的示例:

$ pytest --html=report.html

支持并發(fā)執(zhí)行

???????與unittest不同奥额,pytest具有內(nèi)置并發(fā)執(zhí)行功能。pytest-xdist是一個非常流行的第三方插件访诱,可用于實現(xiàn)分布式測試和多進程測試垫挨。以下是一個使用xdist插件并發(fā)運行測試的示例:

$ pytest -n 4

這里,-n參數(shù)告訴pytest使用4個進程來運行測試盐数。

斷言詳細信息

???????當測試失敗時棒拂,pytest會在控制臺上提供更詳細的錯誤信息,以便開發(fā)人員更容易地調(diào)試代碼玫氢。例如帚屉,以下是一個使用pytest的詳細錯誤信息的示例:

E       assert 'foo'.upper() == 'FOO'
E         AssertionError: assert 'FOO' == 'FOO '
E           - FOO
E           + FOO

???????pytest還提供了其他工具來幫助開發(fā)人員更輕松地查看和分析測試結(jié)果,例如pytest-watch用于自動重新運行測試漾峡,pytest-cov用于測量測試覆蓋率等等攻旦。

結(jié)論

???????本文對比了Python測試框架中的unittest和pytest之間的差異,包括用例編寫規(guī)則生逸、前置和后置方法牢屋、參數(shù)化、斷言功能槽袄、用例執(zhí)行和報告生成等方面烙无。盡管它們有著相同的目標和基本特征,但在實際應用過程中表現(xiàn)出了不同的特點遍尺。
???????pytest比unittest更加靈活截酷、易用、高效和可擴展乾戏,因此建議優(yōu)先考慮使用pytest進行Python測試迂苛。
???????除了本文中提到的功能之外三热,pytest還具有其他許多有用的特性,例如參數(shù)化三幻、fixture管理就漾、插件系統(tǒng)、并發(fā)執(zhí)行念搬、詳細斷言信息等抑堡,可以進一步提高測試效率和質(zhì)量。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末朗徊,一起剝皮案震驚了整個濱河市夷野,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌荣倾,老刑警劉巖悯搔,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異舌仍,居然都是意外死亡妒貌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門铸豁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灌曙,“玉大人,你說我怎么就攤上這事节芥≡诖蹋” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵头镊,是天一觀的道長蚣驼。 經(jīng)常有香客問我,道長相艇,這世上最難降的妖魔是什么颖杏? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮坛芽,結(jié)果婚禮上循榆,老公的妹妹穿的比我還像新娘炼鞠。我一直安慰自己店煞,他們只是感情好申鱼,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著活喊,像睡著了一般丐膝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天尤误,我揣著相機與錄音,去河邊找鬼结缚。 笑死损晤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的红竭。 我是一名探鬼主播尤勋,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼茵宪!你這毒婦竟也來了最冰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤稀火,失蹤者是張志新(化名)和其女友劉穎暖哨,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凰狞,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡篇裁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了赡若。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片达布。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖逾冬,靈堂內(nèi)的尸體忽然破棺而出黍聂,到底是詐尸還是另有隱情,我是刑警寧澤身腻,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布产还,位于F島的核電站,受9級特大地震影響嘀趟,放射性物質(zhì)發(fā)生泄漏雕沉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一去件、第九天 我趴在偏房一處隱蔽的房頂上張望坡椒。 院中可真熱鬧,春花似錦尤溜、人聲如沸倔叼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丈攒。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間巡验,已是汗流浹背际插。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留显设,地道東北人框弛。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像捕捂,于是被迫代替她去往敵國和親瑟枫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容