天天看點

三種最流行的Python單元測試架構unittest,nose和pytest,我該用哪一個?

立志做國内自動化/AI測試領域最好的原創公衆号。歡迎微信關注公号"測試不将就"(ID: awesometest),更多原創文章在路上。我們的口号是:“插上自動化/AI的翅膀,軟體測試也能高大上”,同時會釋出關于Python開發, 持續內建等精彩文章。

作者:資深碼農/技術寫作者,歡迎添加作者微信(slxiaozju)交流。

PART I: 前言

在進行Python程式單元測試時,測試架構的選型是一個首要的問題。面對衆多Python單元測試架構,我應該選擇哪一個?

本文将探讨這個問題。文章的結構如下。首先,介紹單元測試,架構以及測試架構的基本概念;接着,介紹三種最流行的Python單元測試架構,分别是unittest, nose和pytest;然後,介紹作者關于Python單元測試架構選型的思考和心得;最後,總結全文。

PART 2: 基本概念

在介紹具體的Python單元測試架構之前,我們先來回顧一些基本概念。

什麼是單元測試?

單元測試是軟體測試的一種類型。顧名思義,單元測試就是測試的對象是程式中的最小單元的測試。程式的最小單元可以是一個函數,一個類,也可以是函數的組合,類的組合。

單元測試是軟體測試中最低級别的測試活動,與之相對的更進階别的測試有子產品測試,內建系統和系統測試等。單元測試一般由軟體開發者而不是獨立的測試工程師完成。另外,單元測試有一個隐含的性質,那就是單元測試天然就是自動化的,單元測試屬于自動化測試。

什麼是架構?

首先,架構是一個“架子”。這個架子能夠完成領域内基礎的、重要的功能。基于這個已有的架子,我們可以将重心放在面向業務的開發上。

其次,架構也是一個“框框”。“框框”為我們設定了有形和無形的限制。所謂有形的限制,就是我們的開發工作需要符合架構的定義、與架構相容。所謂無形的限制,就是我們的開發工作需要承受架構的缺點和不足(畢竟,沒有十全十美的架構)。

什麼是測試架構?

我們知道,軟體測試分為手工測試和自動化測試。需要注意的是,一般隻有自動化測試才有架構的概念。(自動化)測試架構,需要提供自動化測試用例編寫、自動化測試用例執行、自動化測試報告生成等基礎功能。

有了測試架構,我們隻需要完成和業務高度相關的測試用例設計和實作即可。另外,架構會為我們處理好複雜度與擴充性的問題,我們無需為此操心。

有了這些概念作為支撐,我們就很容易了解什麼是Python單元測試架構了。所謂Python單元測試架構,就是面向Python程式設計語言,服務于Python單元測試的自動化測試架構。

PART 3:主流架構

Python單元測試架構有很多,我們介紹最流行的三種。

1,unittest

unittest是Python标準庫中自帶的單元測試架構。unittest有時候也被稱為PyUnit。就像JUnit是Java語言的标準單元測試架構一樣,unittest(PyUnit)則是Python語言的标準單元測試架構。

unittest支援自動化測試,測試用例的初始化和關閉,測試用例的聚合等功能。unittest有一個很重要的特性:它通過類(class)的方式,将測試用例組織在一起。

一個簡單的示例如下:

importunittest
 
class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')
 
if__name__=='__main__':
    unittest.main()
           

執行結果:

...

---------------------              Ran1 tests in 0.000s              OK
           

需要注意的是,unittest有一個關聯子產品unittest2。但是unittest2僅适用于Python 2.4-2.6。這是因為,從Python 2.7開始,unittest增加一些新的特性。為了在老的版本Python 2.4-2.6支援這些特性,提供了unittest2這個庫。對于Python 2.7及之後的版本,unittest是唯一的。

2,nose

nose是Python的一個第三方單元測試架構。這意味着,如果要使用nose,需要先顯式安裝它:

pip install nose
           

與unittest不同的是,nose的測試用例并不限制于類。任何函數和類,隻要名稱比對一定的條件(例如,以test開頭或以test結尾等),都會被自動識别為測試用例;并且,為了相容unittest, 所有的基于unitest編寫的測試用例,也會被nose自動識别為。

一個簡單的nose單元測試示例如下:

import nose
 
def test_example ():
    pass
 
if __name__ == '__main__':
    nose.runmodule()
           

執行結果:

...              ---------------------              Ran1 tests in 0.000s              OK
           

需要注意的是,nose已經進入維護模式,從github (https://github.com/nose-devs/

nose/commits/master)上可以看到,nose最近的一次代碼送出還是在2016年5月4日。繼承nose的是nose2,但要注意的是,nose2并不支援nose的全部功能,它們的差別可以參見:

https://nose2.readthedocs.io/en/latest/differences.html。

nose2的主要目的是擴充Python的标準單元測試庫unittest,是以它的定位是“帶插件的unittest”。nose2提供的插件,例如測試用例加載器,覆寫度報告生成器,并行測試等内置插件和第三方插件,讓單元測試變得更加完善。

3,pytest

pytest是Python另一個第三方單元測試庫。它的目的是讓單元測試變得更容易,并且也能擴充到支援應用層面複雜的功能測試。

pytest的特性有:

1)支援用簡單的assert語句實作豐富的斷言,無需複雜的self.assert*函數

2)自動識别測試子產品和測試函數

3)相容unittest和nose測試集

4)支援Python3和PyPy3

5)豐富的插件生态,已有300多個各式各樣的插件,和活躍的社群

pytest一個簡單的示例如下:

def inc(x):

    return x +1
 
def test_answer():
    assert inc(3) == 5
           

執行結果如下:​​​​​​​

$ pytest
============================= test session starts=============================
collected 1 items
test_sample.py F
================================== FAILURES===================================
_________________________________ test_answer_________________________________
    def test_answer():
>       assert inc(3)== 5
E       assert 4 == 5
E        +  where 4 = inc(3)
 
test_sample.py:5: AssertionError
========================== 1 failed in 0.04 seconds===========================
           

PART 4: 架構選型

(1) 從入門難度看,pytest/nose優于unittest

雖然unittest是Python自帶的單元測試庫,但是要上手unittest是有難度的,既需要了解testrunner, testsuite, testcase等基本概念,還需要熟悉面向對象程式設計。而pytest/nose則為我們隐藏了這些細節,因而能夠降低入門單元測試的難度。

對于有一定Python程式設計基礎的人來說,unittest是适合的;對于Python程式設計基礎較弱的人來說,nose和pytest則比較适合。另外,對比nose和pytest,一般認為pytest的入門難度更低。

(2) 同為第三方庫,pytest的生态優于nose/nose2

我們知道,nose已經進入了維護模式,取代者是nose2。相比nose2,pytest的生态無疑更具優勢,社群的活躍度也更高。

例如,在github上,截止現在,pytest的STAR數量是4229,而nose2的STAR數量是558;pytest的送出數量是10384,而nose2的送出數量是917。最重要的,pytest的插件數量是300多個,遠高于nose2的20多個插件。

如果隻需要基本的插件,那麼nose和pytest都是适合的;如果追求單元測試更豐富的插件,那麼pytest更适合。

(3) 從通用性角度看,pytest優于unittest和nose

與unittest/nose不同的是,pytest不僅能用于單元測試,還能用于更進階别的,面向應用的功能測試。是以,如果需要進行更進階别的測試,則适合采用Pytest。

PART 5: 總結

在進行Python程式測試時,測試架構的選型是一個重要的問題。衆多測試架構之間,我到底應該選擇哪一個?

本文對比了unittest,nose和pytest這三種最流行的Python單元測試測試,指出了各個架構的特點,指出了在不同場景和不同需求下,哪一種架構更适合。當然,本文的分析還是比較初步的,在實際中,還需要結合具體情況深入分析後再做決定。

立志做國内自動化/AI測試領域最好的原創公衆号。歡迎微信關注公号"測試不将就"(ID: awesometest),更多原創文章在路上。我們的口号是:“插上自動化/AI的翅膀,軟體測試也能高大上”,同時會釋出關于Python開發, 持續內建等精彩文章。

作者:資深碼農/技術寫作者,歡迎添加作者微信(slxiaozju)交流