unittest — 單元測試框架

原始碼: Lib/unittest/__init__.py


(如果您已經熟悉測試的基本概念,您可能想跳到斷言方法列表。)

unittest 單元測試框架最初受 JUnit 的啟發,並且與其他語言中的主要單元測試框架具有相似的風味。它支援測試自動化、共享測試的設定和關閉程式碼、將測試聚合到集合中,以及測試與報告框架的獨立性。

為了實現這一點,unittest 以面向物件的方式支援一些重要概念

測試裝置

測試裝置 表示執行一個或多個測試所需的準備工作,以及任何相關的清理操作。例如,這可能涉及建立臨時或代理資料庫、目錄,或啟動伺服器程序。

測試用例

測試用例 是測試的單個單元。它檢查對特定輸入集的特定響應。unittest 提供了一個基類 TestCase,可用於建立新的測試用例。

測試套件

測試套件 是測試用例、測試套件或兩者的集合。它用於聚合應該一起執行的測試。

測試執行器

測試執行器 是一個協調測試執行並將結果提供給使用者的元件。執行器可以使用圖形介面、文字介面,或返回一個特殊值來指示執行測試的結果。

參見

模組 doctest

另一個具有非常不同風格的測試支援模組。

簡單的 Smalltalk 測試:使用模式

Kent Beck 關於使用 unittest 共享的模式的測試框架的原始論文。

pytest

第三方單元測試框架,具有更輕量級的編寫測試語法。例如,assert func(10) == 42

Python 測試工具分類

Python 測試工具的廣泛列表,包括功能測試框架和模擬物件庫。

Python 測試郵件列表

一個專門討論 Python 中的測試和測試工具的特殊興趣小組。

Python 原始碼發行版中的指令碼 Tools/unittestgui/unittestgui.py 是一個用於測試發現和執行的 GUI 工具。這主要是為了方便那些剛接觸單元測試的人使用。對於生產環境,建議測試由持續整合系統驅動,例如 BuildbotJenkinsGitHub ActionsAppVeyor

基本示例

unittest 模組提供了一組豐富的工具來構建和執行測試。本節演示了一小部分工具足以滿足大多數使用者的需求。

這是一個測試三個字串方法的簡短指令碼

import unittest

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'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

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

透過子類化 unittest.TestCase 來建立測試用例。三個單獨的測試由名稱以字母 test 開頭的方法定義。此命名約定會告知測試執行器哪些方法表示測試。

每個測試的關鍵是對 assertEqual() 的呼叫,以檢查預期結果; assertTrue()assertFalse() 來驗證條件;或 assertRaises() 來驗證是否引發了特定異常。這些方法代替了 assert 語句,以便測試執行器可以累積所有測試結果並生成報告。

setUp()tearDown() 方法允許您定義將在每個測試方法之前和之後執行的指令。它們在組織測試程式碼部分進行了更詳細的介紹。

最後一塊顯示了執行測試的簡單方法。unittest.main() 為測試指令碼提供了命令列介面。從命令列執行時,上面的指令碼會生成如下所示的輸出

...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

-v 選項傳遞給您的測試指令碼將指示 unittest.main() 啟用更高級別的詳細程度,併產生以下輸出

test_isupper (__main__.TestStringMethods.test_isupper) ... ok
test_split (__main__.TestStringMethods.test_split) ... ok
test_upper (__main__.TestStringMethods.test_upper) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

上面的示例顯示了最常用的 unittest 功能,這些功能足以滿足許多日常測試需求。其餘文件從第一原理探討了完整的功能集。

在 3.11 版本中變更: 現在不推薦從測試方法返回一個值(除了預設的 None 值)。

命令列介面

可以從命令列使用 unittest 模組來執行模組、類甚至單個測試方法中的測試。

python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method

您可以傳入一個列表,其中包含模組名稱、完全限定的類名或方法名的任意組合。

也可以透過檔案路徑指定測試模組。

python -m unittest tests/test_something.py

這允許您使用 shell 檔名補全來指定測試模組。指定的檔案仍然必須可以作為模組匯入。透過刪除“.py”並將路徑分隔符轉換為“.”,將路徑轉換為模組名稱。如果要執行一個不能作為模組匯入的測試檔案,您應該直接執行該檔案。

您可以透過傳入 -v 標誌來執行更詳細(更高詳細程度)的測試。

python -m unittest -v test_module

在不帶引數執行時,將啟動測試發現

python -m unittest

有關所有命令列選項的列表

python -m unittest -h

在 3.2 版本中變更: 在早期版本中,只能執行單個測試方法,而不能執行模組或類。

命令列選項

unittest 支援以下命令列選項

-b, --buffer

在測試執行期間,標準輸出和標準錯誤流會被緩衝。在透過測試期間的輸出會被丟棄。在測試失敗或錯誤時,輸出會正常回顯,並新增到失敗訊息中。

-c, --catch

在測試執行期間按下 Control-C 會等待當前測試結束,然後報告到目前為止的所有結果。第二次按下 Control-C 會引發正常的 KeyboardInterrupt 異常。

有關提供此功能的函式,請參閱 訊號處理

-f, --failfast

在第一次出現錯誤或失敗時停止測試執行。

-k

僅執行與模式或子字串匹配的測試方法和類。此選項可以多次使用,在這種情況下,將包含與任何給定模式匹配的所有測試用例。

包含萬用字元 ( * ) 的模式將使用 fnmatch.fnmatchcase() 與測試名稱進行匹配;否則,將使用簡單的區分大小寫的子字串匹配。

模式將與測試載入器匯入的完全限定的測試方法名稱進行匹配。

例如,-k foo 將匹配 foo_tests.SomeTest.test_somethingbar_tests.SomeTest.test_foo,但不匹配 bar_tests.FooTest.test_something

--locals

在回溯中顯示區域性變數。

--durations N

顯示 N 個最慢的測試用例(N=0 表示全部)。

在 3.2 版本中新增: 添加了命令列選項 -b-c-f

在 3.5 版本中新增: 添加了命令列選項 --locals

在 3.7 版本中新增: 添加了命令列選項 -k

在 3.12 版本中新增: 添加了命令列選項 --durations

命令列還可以用於測試發現,用於執行專案中的所有測試或僅執行一部分測試。

測試發現

在 3.2 版本中新增。

Unittest 支援簡單的測試發現。為了與測試發現相容,所有測試檔案都必須是可以從專案的頂層目錄匯入的模組(這意味著它們的檔名必須是有效的識別符號)。

測試發現是在 TestLoader.discover() 中實現的,但也可以從命令列使用。基本的命令列用法是

cd project_directory
python -m unittest discover

註解

作為快捷方式,python -m unittest 等同於 python -m unittest discover。如果您想將引數傳遞給測試發現,則必須顯式使用 discover 子命令。

discover 子命令具有以下選項

-v, --verbose

詳細輸出

-s, --start-directory directory

啟動發現的目錄(預設值為 .

-p, --pattern pattern

匹配測試檔案的模式(預設值為 test*.py

-t, --top-level-directory directory

專案的頂層目錄(預設為起始目錄)

可以將 -s-p-t 選項按該順序作為位置引數傳入。以下兩個命令列是等效的

python -m unittest discover -s project_directory -p "*_test.py"
python -m unittest discover project_directory "*_test.py"

除了作為路徑之外,還可以將包名稱(例如 myproject.subpackage.test)作為起始目錄傳遞。您提供的包名稱將被匯入,並且其在檔案系統上的位置將用作起始目錄。

注意

測試發現透過匯入來載入測試。一旦測試發現從您指定的起始目錄找到所有測試檔案,它就會將路徑轉換為要匯入的包名稱。例如,foo/bar/baz.py 將作為 foo.bar.baz 匯入。

如果您在全域性安裝了一個包,並嘗試在包的不同副本上進行測試發現,那麼匯入可能會從錯誤的位置發生。如果發生這種情況,測試發現會警告您並退出。

如果您將起始目錄作為包名稱而不是目錄路徑提供,那麼發現會假定它匯入的任何位置都是您打算的位置,因此您不會收到警告。

測試模組和包可以透過 load_tests 協議自定義測試載入和發現。

在 3.4 版本中變更: 測試發現支援起始目錄的名稱空間包。請注意,您還需要指定頂層目錄(例如 python -m unittest discover -s root/namespace -t root)。

在 3.11 版本中變更: unittest 在 Python 3.11 中放棄了對名稱空間包的支援。自 Python 3.7 以來,它一直處於損壞狀態。包含測試的起始目錄和子目錄必須是具有 __init__.py 檔案的常規包。

包含起始目錄的目錄仍然可以是名稱空間包。在這種情況下,您需要將起始目錄指定為點分隔的包名稱,並顯式指定目標目錄。例如

# proj/  <-- current directory
#   namespace/
#     mypkg/
#       __init__.py
#       test_mypkg.py

python -m unittest discover -s namespace.mypkg -t .

組織測試程式碼

單元測試的基本構建塊是測試用例 — 必須設定並檢查正確性的單個場景。在 unittest 中,測試用例由 unittest.TestCase 例項表示。要建立自己的測試用例,您必須編寫 TestCase 的子類,或者使用 FunctionTestCase

TestCase 例項的測試程式碼應該是完全獨立的,這樣它既可以單獨執行,也可以與任意數量的其他測試用例組合執行。

最簡單的 TestCase 子類將簡單地實現一個測試方法(即名稱以 test 開頭的方法)以執行特定的測試程式碼

import unittest

class DefaultWidgetSizeTestCase(unittest.TestCase):
    def test_default_widget_size(self):
        widget = Widget('The widget')
        self.assertEqual(widget.size(), (50, 50))

請注意,為了測試某些內容,我們使用 assert* 方法,這些方法由 TestCase 基類提供。如果測試失敗,將引發帶有解釋性訊息的異常,並且 unittest 會將測試用例標識為失敗。任何其他異常都將被視為錯誤

測試可能有很多,並且它們的設定可能會重複。幸運的是,我們可以透過實現一個名為 setUp() 的方法來分解設定程式碼,測試框架會自動為我們執行的每個測試呼叫該方法

import unittest

class WidgetTestCase(unittest.TestCase):
    def setUp(self):
        self.widget = Widget('The widget')

    def test_default_widget_size(self):
        self.assertEqual(self.widget.size(), (50,50),
                         'incorrect default size')

    def test_widget_resize(self):
        self.widget.resize(100,150)
        self.assertEqual(self.widget.size(), (100,150),
                         'wrong size after resize')

註解

各種測試的執行順序是透過對測試方法名稱按照字串的內建排序進行排序來確定的。

如果在測試執行時 setUp() 方法引發異常,框架將認為測試發生了錯誤,並且不會執行測試方法。

類似地,我們可以提供一個 tearDown() 方法,該方法在測試方法執行後進行清理

import unittest

class WidgetTestCase(unittest.TestCase):
    def setUp(self):
        self.widget = Widget('The widget')

    def tearDown(self):
        self.widget.dispose()

如果 setUp() 成功,則無論測試方法是否成功,都將執行 tearDown()

用於測試程式碼的這種工作環境稱為測試裝置。建立一個新的 TestCase 例項,作為用於執行每個單獨測試方法的唯一測試裝置。因此,setUp()tearDown()__init__() 將每個測試呼叫一次。

建議您使用 TestCase 實現來根據它們測試的功能將測試組合在一起。unittest 提供了一種機制:測試套件,由 unittestTestSuite 類表示。在大多數情況下,呼叫 unittest.main() 將會做正確的事情,併為您收集模組的所有測試用例並執行它們。

但是,如果您想自定義測試套件的構建,則可以自己完成

def suite():
    suite = unittest.TestSuite()
    suite.addTest(WidgetTestCase('test_default_widget_size'))
    suite.addTest(WidgetTestCase('test_widget_resize'))
    return suite

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())

您可以將測試用例和測試套件的定義放在與要測試的程式碼相同的模組中(例如 widget.py),但是將測試程式碼放在單獨的模組中(例如 test_widget.py)有幾個優點

  • 測試模組可以從命令列獨立執行。

  • 測試程式碼可以更容易地與釋出的程式碼分離。

  • 在沒有充分理由的情況下,更改測試程式碼以適應其測試的程式碼的誘惑較小。

  • 測試程式碼的修改頻率應遠低於其測試的程式碼。

  • 可以更輕鬆地重構被測試的程式碼。

  • 無論如何,用 C 編寫的模組的測試必須在單獨的模組中,那麼為什麼不保持一致呢?

  • 如果測試策略發生變化,則無需更改原始碼。

重用舊的測試程式碼

一些使用者會發現他們有現有的測試程式碼,他們希望從 unittest 執行,而無需將每個舊的測試函式轉換為 TestCase 子類。

因此,unittest 提供了一個 FunctionTestCase 類。此 TestCase 的子類可用於包裝現有的測試函式。還可以提供設定和拆卸函式。

給定以下測試函式

def testSomething():
    something = makeSomething()
    assert something.name is not None
    # ...

可以按如下方式建立等效的測試用例例項,並帶有可選的設定和拆卸方法

testcase = unittest.FunctionTestCase(testSomething,
                                     setUp=makeSomethingDB,
                                     tearDown=deleteSomethingDB)

註解

即使可以使用 FunctionTestCase 將現有的測試庫快速轉換為基於 unittest 的系統,也不建議使用這種方法。花時間設定正確的 TestCase 子類將使將來的測試重構變得無限容易。

在某些情況下,現有測試可能已使用 doctest 模組編寫。如果是這樣,doctest 提供了一個 DocTestSuite 類,可以從現有的基於 doctest 的測試中自動構建 unittest.TestSuite 例項。

跳過測試和預期失敗

在 3.1 版本中新增。

Unittest 支援跳過單個測試方法,甚至整個測試類。此外,它還支援將測試標記為“預期失敗”,這是一種已損壞並將失敗的測試,但不應將其計為 TestResult 上的失敗。

跳過測試只是使用 skip() 裝飾器 或其條件變體之一,呼叫 TestCase.skipTest()setUp() 或測試方法中,或直接引發 SkipTest

基本的跳過如下所示

class MyTestCase(unittest.TestCase):

    @unittest.skip("demonstrating skipping")
    def test_nothing(self):
        self.fail("shouldn't happen")

    @unittest.skipIf(mylib.__version__ < (1, 3),
                     "not supported in this library version")
    def test_format(self):
        # Tests that work for only a certain version of the library.
        pass

    @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
    def test_windows_support(self):
        # windows specific testing code
        pass

    def test_maybe_skipped(self):
        if not external_resource_available():
            self.skipTest("external resource not available")
        # test code that depends on the external resource
        pass

這是在詳細模式下執行上述示例的輸出

test_format (__main__.MyTestCase.test_format) ... skipped 'not supported in this library version'
test_nothing (__main__.MyTestCase.test_nothing) ... skipped 'demonstrating skipping'
test_maybe_skipped (__main__.MyTestCase.test_maybe_skipped) ... skipped 'external resource not available'
test_windows_support (__main__.MyTestCase.test_windows_support) ... skipped 'requires Windows'

----------------------------------------------------------------------
Ran 4 tests in 0.005s

OK (skipped=4)

可以像方法一樣跳過類

@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
    def test_not_run(self):
        pass

TestCase.setUp() 也可以跳過測試。當需要設定的資源不可用時,這很有用。

預期失敗使用 expectedFailure() 裝飾器。

class ExpectedFailureTestCase(unittest.TestCase):
    @unittest.expectedFailure
    def test_fail(self):
        self.assertEqual(1, 0, "broken")

透過建立一個在想要跳過測試時在測試上呼叫 skip() 的裝飾器,可以輕鬆地推出自己的跳過裝飾器。此裝飾器會跳過測試,除非傳遞的物件具有某個屬性

def skipUnlessHasattr(obj, attr):
    if hasattr(obj, attr):
        return lambda func: func
    return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))

以下裝飾器和異常實現測試跳過和預期失敗

@unittest.skip(reason)

無條件跳過被裝飾的測試。reason 應該描述為什麼跳過測試。

@unittest.skipIf(condition, reason)

如果 condition 為真,則跳過被裝飾的測試。

@unittest.skipUnless(condition, reason)

除非 condition 為真,否則跳過被裝飾的測試。

@unittest.expectedFailure

將測試標記為預期的失敗或錯誤。 如果測試在測試函式本身(而不是在其中一個 測試夾具 方法中)失敗或出錯,則將其視為成功。 如果測試透過,則將其視為失敗。

exception unittest.SkipTest(reason)

丟擲此異常以跳過測試。

通常,您可以使用 TestCase.skipTest() 或跳過裝飾器之一,而不是直接丟擲此異常。

跳過的測試將不會在其周圍執行 setUp()tearDown()。 跳過的類將不會執行 setUpClass()tearDownClass()。 跳過的模組將不會執行 setUpModule()tearDownModule()

使用子測試區分測試迭代

在 3.4 版本中新增。

當您的測試之間存在很小的差異時,例如某些引數,unittest 允許您使用 subTest() 上下文管理器在測試方法的主體中區分它們。

例如,以下測試

class NumbersTest(unittest.TestCase):

    def test_even(self):
        """
        Test that numbers between 0 and 5 are all even.
        """
        for i in range(0, 6):
            with self.subTest(i=i):
                self.assertEqual(i % 2, 0)

將產生以下輸出

======================================================================
FAIL: test_even (__main__.NumbersTest.test_even) (i=1)
Test that numbers between 0 and 5 are all even.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 11, in test_even
    self.assertEqual(i % 2, 0)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest.test_even) (i=3)
Test that numbers between 0 and 5 are all even.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 11, in test_even
    self.assertEqual(i % 2, 0)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest.test_even) (i=5)
Test that numbers between 0 and 5 are all even.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 11, in test_even
    self.assertEqual(i % 2, 0)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0

如果不使用子測試,執行會在第一次失敗後停止,並且錯誤將更難以診斷,因為不會顯示 i 的值

======================================================================
FAIL: test_even (__main__.NumbersTest.test_even)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 32, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

類和函式

本節深入描述 unittest 的 API。

測試用例

class unittest.TestCase(methodName='runTest')

TestCase 類的例項表示 unittest 世界中的邏輯測試單元。 此類旨在用作基類,並透過具體的子類實現特定的測試。 此類實現了測試執行器驅動測試所需的介面,以及測試程式碼可以用來檢查和報告各種失敗的方法。

每個 TestCase 例項將執行一個基本方法:名為 methodName 的方法。 在 TestCase 的大多數用法中,您既不會更改 methodName 也不會重新實現預設的 runTest() 方法。

在 3.2 版本中更改: TestCase 可以在不提供 methodName 的情況下成功例項化。 這使得從互動式直譯器中試驗 TestCase 變得更容易。

TestCase 例項提供三組方法:一組用於執行測試,另一組用於測試實現以檢查條件和報告失敗,以及一些查詢方法,允許收集有關測試本身的資訊。

第一組(執行測試)中的方法是

setUp()

呼叫以準備測試夾具的方法。 這在呼叫測試方法之前立即呼叫; 除了 AssertionErrorSkipTest,此方法引發的任何異常都將被視為錯誤而不是測試失敗。 預設實現不執行任何操作。

tearDown()

在呼叫測試方法並記錄結果後立即呼叫的方法。 即使測試方法引發了異常,也會呼叫此方法,因此子類中的實現可能需要特別注意檢查內部狀態。 除了 AssertionErrorSkipTest 之外,此方法引發的任何異常都將被視為附加錯誤而不是測試失敗(因此會增加報告錯誤的總數)。 無論測試方法的結果如何,只有在 setUp() 成功時,才會呼叫此方法。 預設實現不執行任何操作。

setUpClass()

在執行單個類中的測試之前呼叫的類方法。 setUpClass 使用類作為唯一引數呼叫,並且必須被裝飾為 classmethod()

@classmethod
def setUpClass(cls):
    ...

有關詳細資訊,請參見 類和模組夾具

在 3.2 版本中新增。

tearDownClass()

在單個類中的測試執行後呼叫的類方法。 tearDownClass 使用類作為唯一引數呼叫,並且必須被裝飾為 classmethod()

@classmethod
def tearDownClass(cls):
    ...

有關詳細資訊,請參見 類和模組夾具

在 3.2 版本中新增。

run(result=None)

執行測試,將結果收集到作為 result 傳遞的 TestResult 物件中。 如果省略 result 或為 None,則會建立一個臨時結果物件(透過呼叫 defaultTestResult() 方法)並使用。 結果物件返回給 run() 的呼叫者。

只需呼叫 TestCase 例項即可獲得相同的效果。

3.3 版本已更改: run 的先前版本不返回結果。呼叫例項也不返回結果。

skipTest(reason)

在測試方法或 setUp() 中呼叫此方法會跳過當前測試。有關更多資訊,請參見 跳過測試和預期失敗

在 3.1 版本中新增。

subTest(msg=None, **params)

返回一個上下文管理器,它將封閉的程式碼塊作為子測試執行。msgparams 是可選的,任意的值,當子測試失敗時會顯示這些值,以便您可以清楚地識別它們。

一個測試用例可以包含任意數量的子測試宣告,並且它們可以任意巢狀。

有關更多資訊,請參見 使用子測試區分測試迭代

在 3.4 版本中新增。

debug()

執行測試而不收集結果。這允許測試引發的異常傳播到呼叫者,並且可以用於支援在偵錯程式下執行測試。

TestCase 類提供了幾個斷言方法來檢查和報告失敗。下表列出了最常用的方法(有關更多斷言方法,請參見下表)

方法

檢查

新增於

assertEqual(a, b)

a == b

assertNotEqual(a, b)

a != b

assertTrue(x)

bool(x) is True

assertFalse(x)

bool(x) is False

assertIs(a, b)

a is b

3.1

assertIsNot(a, b)

a is not b

3.1

assertIsNone(x)

x is None

3.1

assertIsNotNone(x)

x is not None

3.1

assertIn(a, b)

a in b

3.1

assertNotIn(a, b)

a not in b

3.1

assertIsInstance(a, b)

isinstance(a, b)

3.2

assertNotIsInstance(a, b)

not isinstance(a, b)

3.2

所有斷言方法都接受一個 msg 引數,如果指定了該引數,則在失敗時用作錯誤訊息(另請參見 longMessage)。請注意,msg 關鍵字引數只能在用作上下文管理器時傳遞給 assertRaises()assertRaisesRegex()assertWarns()assertWarnsRegex()

assertEqual(first, second, msg=None)

測試 firstsecond 是否相等。如果值不相等,則測試將失敗。

此外,如果 firstsecond 是完全相同的型別,並且是 list、tuple、dict、set、frozenset 或 str 中的一種,或者任何子類使用 addTypeEqualityFunc() 註冊的型別,則會呼叫特定於型別的相等函式,以便生成更有用的預設錯誤訊息(另請參見 特定於型別的方法列表)。

3.1 版本已更改: 添加了自動呼叫特定於型別的相等函式。

3.2 版本已更改: 添加了 assertMultiLineEqual() 作為比較字串的預設型別相等函式。

assertNotEqual(first, second, msg=None)

測試 firstsecond 是否不相等。如果值比較相等,則測試將失敗。

assertTrue(expr, msg=None)
assertFalse(expr, msg=None)

測試 expr 為真(或假)。

請注意,這等效於 bool(expr) is True,而不是 expr is True(對於後者,請使用 assertIs(expr, True))。當有更具體的方法可用時(例如,assertEqual(a, b) 而不是 assertTrue(a == b)),也應該避免使用此方法,因為在失敗的情況下它們會提供更好的錯誤訊息。

assertIs(first, second, msg=None)
assertIsNot(first, second, msg=None)

測試 firstsecond 是否是(或不是)同一個物件。

在 3.1 版本中新增。

assertIsNone(expr, msg=None)
assertIsNotNone(expr, msg=None)

測試 expr 是(或不是) None

在 3.1 版本中新增。

assertIn(member, container, msg=None)
assertNotIn(member, container, msg=None)

測試 member 是否在 container 中(或不在其中)。

在 3.1 版本中新增。

assertIsInstance(obj, cls, msg=None)
assertNotIsInstance(obj, cls, msg=None)

測試 obj 是否(或不是)cls 的例項(cls 可以是一個類或一個類元組,由 isinstance() 支援)。要檢查確切的型別,請使用 assertIs(type(obj), cls)

在 3.2 版本中新增。

還可以使用以下方法檢查異常、警告和日誌訊息的產生

方法

檢查

新增於

assertRaises(exc, fun, *args, **kwds)

fun(*args, **kwds) 丟擲 exc

assertRaisesRegex(exc, r, fun, *args, **kwds)

fun(*args, **kwds) 丟擲 exc 並且訊息與正則表示式 r 匹配

3.1

assertWarns(warn, fun, *args, **kwds)

fun(*args, **kwds) 丟擲 warn

3.2

assertWarnsRegex(warn, r, fun, *args, **kwds)

fun(*args, **kwds) 丟擲 warn 並且訊息與正則表示式 r 匹配

3.2

assertLogs(logger, level)

with 程式碼塊在 logger 上記錄,最低級別為 level

3.4

assertNoLogs(logger, level)

with 程式碼塊不在

logger 上記錄,最低級別為 level

3.10

assertRaises(exception, callable, *args, **kwds)
assertRaises(exception, *, msg=None)

測試當使用任何位置或關鍵字引數呼叫 callable 時,是否會丟擲異常,這些引數也會傳遞給 assertRaises()。如果丟擲 exception 則測試透過,如果丟擲其他異常則是錯誤,如果沒有丟擲異常則測試失敗。要捕獲一組異常中的任何一個,可以將包含異常類的元組作為 exception 傳遞。

如果僅給出 exception 且可能給出 msg 引數,則返回上下文管理器,以便可以內聯編寫被測試的程式碼而不是作為函式

with self.assertRaises(SomeException):
    do_something()

當用作上下文管理器時,assertRaises() 接受附加的關鍵字引數 msg

上下文管理器將捕獲的異常物件儲存在其 exception 屬性中。 如果目的是對引發的異常執行其他檢查,這將很有用

with self.assertRaises(SomeException) as cm:
    do_something()

the_exception = cm.exception
self.assertEqual(the_exception.error_code, 3)

在 3.1 版本中更改: 增加了使用 assertRaises() 作為上下文管理器的功能。

在 3.2 版本中更改: 添加了 exception 屬性。

在 3.3 版本中更改: 當用作上下文管理器時,添加了 msg 關鍵字引數。

assertRaisesRegex(exception, regex, callable, *args, **kwds)
assertRaisesRegex(exception, regex, *, msg=None)

類似於 assertRaises(),但還測試 regex 是否與丟擲的異常的字串表示形式匹配。regex 可以是正則表示式物件或包含適用於 re.search() 的正則表示式的字串。示例

self.assertRaisesRegex(ValueError, "invalid literal for.*XYZ'$",
                       int, 'XYZ')

或者

with self.assertRaisesRegex(ValueError, 'literal'):
   int('XYZ')

在 3.1 版本中新增: assertRaisesRegexp 名稱新增。

在 3.2 版本中更改: 重新命名為 assertRaisesRegex()

在 3.3 版本中更改: 當用作上下文管理器時,添加了 msg 關鍵字引數。

assertWarns(warning, callable, *args, **kwds)
assertWarns(warning, *, msg=None)

測試當使用任何位置或關鍵字引數呼叫 callable 時,是否會觸發警告,這些引數也會傳遞給 assertWarns()。如果觸發了 warning 則測試透過,如果沒有觸發則測試失敗。任何異常都是錯誤。要捕獲一組警告中的任何一個,可以將包含警告類的元組作為 warnings 傳遞。

如果僅給出 warning 且可能給出 msg 引數,則返回上下文管理器,以便可以內聯編寫被測試的程式碼而不是作為函式

with self.assertWarns(SomeWarning):
    do_something()

當用作上下文管理器時,assertWarns() 接受附加的關鍵字引數 msg

上下文管理器將捕獲的警告物件儲存在其 warning 屬性中,並將觸發警告的原始碼行儲存在 filenamelineno 屬性中。 如果目的是對捕獲的警告執行其他檢查,這將很有用

with self.assertWarns(SomeWarning) as cm:
    do_something()

self.assertIn('myfile.py', cm.filename)
self.assertEqual(320, cm.lineno)

此方法的工作方式與呼叫它時存在的警告過濾器無關。

在 3.2 版本中新增。

在 3.3 版本中更改: 當用作上下文管理器時,添加了 msg 關鍵字引數。

assertWarnsRegex(warning, regex, callable, *args, **kwds)
assertWarnsRegex(warning, regex, *, msg=None)

類似於 assertWarns(),但還測試 regex 是否與觸發的警告的訊息匹配。regex 可以是正則表示式物件或包含適合 re.search() 的正則表示式的字串。示例

self.assertWarnsRegex(DeprecationWarning,
                      r'legacy_function\(\) is deprecated',
                      legacy_function, 'XYZ')

或者

with self.assertWarnsRegex(RuntimeWarning, 'unsafe frobnicating'):
    frobnicate('/etc/passwd')

在 3.2 版本中新增。

在 3.3 版本中更改: 當用作上下文管理器時,添加了 msg 關鍵字引數。

assertLogs(logger=None, level=None)

一個上下文管理器,用於測試在 logger 或其子項上是否記錄了至少一條訊息,且該訊息的級別至少為給定的 level

如果給定,logger 應該是一個 logging.Logger 物件,或者是一個給出日誌記錄器名稱的 str。預設值是根日誌記錄器,它將捕獲所有未被非傳播後代日誌記錄器阻止的訊息。

如果給定,level 應該是一個數字日誌級別或其字串等效項(例如,"ERROR"logging.ERROR)。預設值是 logging.INFO

如果 with 程式碼塊內發出的至少一條訊息與 loggerlevel 條件匹配,則測試透過,否則測試失敗。

上下文管理器返回的物件是一個記錄輔助工具,它會跟蹤匹配的日誌訊息。它有兩個屬性:

records

匹配的日誌訊息的 logging.LogRecord 物件列表。

output

包含匹配訊息的格式化輸出的 str 物件列表。

示例

with self.assertLogs('foo', level='INFO') as cm:
    logging.getLogger('foo').info('first message')
    logging.getLogger('foo.bar').error('second message')
self.assertEqual(cm.output, ['INFO:foo:first message',
                             'ERROR:foo.bar:second message'])

在 3.4 版本中新增。

assertNoLogs(logger=None, level=None)

一個上下文管理器,用於測試在 logger 或其子項上是否沒有記錄訊息,且該訊息的級別至少為給定的 level

如果給定,logger 應該是一個 logging.Logger 物件,或者是一個給出日誌記錄器名稱的 str。預設值是根日誌記錄器,它將捕獲所有訊息。

如果給定,level 應該是一個數字日誌級別或其字串等效項(例如,"ERROR"logging.ERROR)。預設值是 logging.INFO

assertLogs() 不同,上下文管理器不會返回任何內容。

在 3.10 版本中新增。

還有其他一些用於執行更具體檢查的方法,例如:

方法

檢查

新增於

assertAlmostEqual(a, b)

round(a-b, 7) == 0

assertNotAlmostEqual(a, b)

round(a-b, 7) != 0

assertGreater(a, b)

a > b

3.1

assertGreaterEqual(a, b)

a >= b

3.1

assertLess(a, b)

a < b

3.1

assertLessEqual(a, b)

a <= b

3.1

assertRegex(s, r)

r.search(s)

3.1

assertNotRegex(s, r)

not r.search(s)

3.2

assertCountEqual(a, b)

ab 具有相同數量的相同元素,而無需考慮順序。

3.2

assertAlmostEqual(first, second, places=7, msg=None, delta=None)
assertNotAlmostEqual(first, second, places=7, msg=None, delta=None)

透過計算差值、四捨五入到給定的小數位數 places (預設值為 7),並與零進行比較,來測試 firstsecond 是否近似相等(或不近似相等)。請注意,這些方法將值四捨五入到給定的小數位數(即類似於 round() 函式),而不是四捨五入到有效位數

如果提供 delta 而不是 places,則 firstsecond 之間的差值必須小於或等於(或大於)delta

同時提供 deltaplaces 將引發 TypeError

在 3.2 版本中更改: assertAlmostEqual() 自動將比較相等的物件視為近似相等。如果物件比較相等,則 assertNotAlmostEqual() 將自動失敗。添加了 delta 關鍵字引數。

assertGreater(first, second, msg=None)
assertGreaterEqual(first, second, msg=None)
assertLess(first, second, msg=None)
assertLessEqual(first, second, msg=None)

根據方法名稱,測試 first 是否分別大於、大於等於、小於或小於等於 second。如果不是,則測試將失敗。

>>> self.assertGreaterEqual(3, 4)
AssertionError: "3" unexpectedly not greater than or equal to "4"

在 3.1 版本中新增。

assertRegex(text, regex, msg=None)
assertNotRegex(text, regex, msg=None)

測試 regex 搜尋是否與 text 匹配(或不匹配)。如果失敗,錯誤訊息將包含模式和 text(或模式和意外匹配的 text 部分)。regex 可以是正則表示式物件或包含適合 re.search() 使用的正則表示式的字串。

在 3.1 版本中新增: assertRegexpMatches 的名稱新增。

在 3.2 版本中更改: 方法 assertRegexpMatches() 已重新命名為 assertRegex()

在 3.2 版本中新增: assertNotRegex()

assertCountEqual(first, second, msg=None)

測試序列 first 是否包含與 second 相同的元素,而忽略它們的順序。如果它們不相同,將生成一個錯誤訊息,列出序列之間的差異。

在比較 firstsecond 時,重複的元素不會被忽略。它驗證每個元素在兩個序列中是否具有相同的計數。等效於:assertEqual(Counter(list(first)), Counter(list(second))),但也可以處理不可雜湊物件的序列。

在 3.2 版本中新增。

assertEqual() 方法將相同型別的物件的相等性檢查分派給不同的型別特定方法。這些方法已經為大多數內建型別實現,但也可以使用 addTypeEqualityFunc() 註冊新方法。

addTypeEqualityFunc(typeobj, function)

註冊一個型別特定的方法,該方法由 assertEqual() 呼叫,以檢查兩個完全相同 typeobj (不是子類) 的物件是否相等。function 必須接受兩個位置引數和一個第三個 msg=None 關鍵字引數,就像 assertEqual() 一樣。當檢測到前兩個引數之間不相等時,它必須引發 self.failureException(msg),並可能在錯誤訊息中提供有用的資訊並詳細解釋不相等之處。

在 3.1 版本中新增。

以下表格總結了 assertEqual() 自動使用的型別特定方法的列表。請注意,通常不需要直接呼叫這些方法。

方法

用於比較

新增於

assertMultiLineEqual(a, b)

字串

3.1

assertSequenceEqual(a, b)

序列

3.1

assertListEqual(a, b)

列表

3.1

assertTupleEqual(a, b)

元組

3.1

assertSetEqual(a, b)

集合或凍結集合

3.1

assertDictEqual(a, b)

字典

3.1

assertMultiLineEqual(first, second, msg=None)

測試多行字串 first 是否等於字串 second。如果不相等,則會在錯誤訊息中包含兩個字串的差異,突出顯示差異。預設情況下,當使用 assertEqual() 比較字串時,會使用此方法。

在 3.1 版本中新增。

assertSequenceEqual(first, second, msg=None, seq_type=None)

測試兩個序列是否相等。如果提供了 seq_type,則 firstsecond 都必須是 seq_type 的例項,否則將引發失敗。如果序列不同,則會構造一條錯誤訊息,顯示兩者之間的差異。

此方法不由 assertEqual() 直接呼叫,但它用於實現 assertListEqual()assertTupleEqual()

在 3.1 版本中新增。

assertListEqual(first, second, msg=None)
assertTupleEqual(first, second, msg=None)

測試兩個列表或元組是否相等。如果不相等,則會構造一個錯誤訊息,僅顯示兩者之間的差異。如果任何一個引數的型別錯誤,也會引發錯誤。預設情況下,當使用 assertEqual() 比較列表或元組時,會使用這些方法。

在 3.1 版本中新增。

assertSetEqual(first, second, msg=None)

測試兩個集合是否相等。如果不相等,則會構造一個錯誤訊息,列出集合之間的差異。預設情況下,當使用 assertEqual() 比較集合或凍結集合時,會使用此方法。

如果 firstsecond 都沒有 set.difference() 方法,則會失敗。

在 3.1 版本中新增。

assertDictEqual(first, second, msg=None)

測試兩個字典是否相等。如果不相等,則會構造一條錯誤訊息,顯示字典中的差異。預設情況下,此方法將用於在呼叫 assertEqual() 時比較字典。

在 3.1 版本中新增。

最後,TestCase 提供了以下方法和屬性

fail(msg=None)

無條件地發出測試失敗訊號,錯誤訊息為 msgNone

failureException

此類屬性給出測試方法引發的異常。如果測試框架需要使用特定的異常,可能需要攜帶其他資訊,它必須對該異常進行子類化,以便與框架“公平競爭”。此屬性的初始值為 AssertionError

longMessage

此類屬性確定當自定義失敗訊息作為 msg 引數傳遞給失敗的 assertXYY 呼叫時會發生什麼。True 是預設值。在這種情況下,自定義訊息會附加到標準失敗訊息的末尾。當設定為 False 時,自定義訊息會替換標準訊息。

可以透過在呼叫 assert 方法之前將例項屬性 self.longMessage 分配給 TrueFalse,在單個測試方法中覆蓋類設定。

類設定在每次測試呼叫之前都會重置。

在 3.1 版本中新增。

maxDiff

此屬性控制斷言方法在失敗時報告差異輸出的最大長度。預設值為 80*8 個字元。受此屬性影響的斷言方法包括 assertSequenceEqual() (包括所有委託給它的序列比較方法),assertDictEqual()assertMultiLineEqual()

maxDiff 設定為 None 表示差異輸出沒有最大長度限制。

在 3.2 版本中新增。

測試框架可以使用以下方法來收集測試資訊

countTestCases()

返回此測試物件表示的測試數量。對於 TestCase 例項,此值始終為 1

defaultTestResult()

返回應用於此測試用例類的測試結果類的例項(如果沒有其他結果例項提供給 run() 方法)。

對於 TestCase 例項,這始終是 TestResult 的例項;TestCase 的子類應根據需要覆蓋此方法。

id()

返回一個字串,標識特定的測試用例。這通常是測試方法的完整名稱,包括模組和類名稱。

shortDescription()

返回測試的描述,如果沒有提供描述,則返回 None。此方法的預設實現返回測試方法的文件字串的第一行(如果可用),否則返回 None

在 3.1 版本中更改: 在 3.1 版本中,即使存在文件字串,也會將測試名稱新增到簡短描述中。這導致了與 unittest 擴充套件的相容性問題,並將測試名稱新增到 TextTestResult(在 Python 3.2 中)。

addCleanup(function, /, *args, **kwargs)

新增一個函式,在 tearDown() 之後呼叫,以清理測試期間使用的資源。函式將按照它們新增的相反順序(後進先出 LIFO)呼叫。呼叫時,會將傳遞給 addCleanup() 的任何引數和關鍵字引數傳遞給它們。

如果 setUp() 失敗,這意味著不會呼叫 tearDown(),那麼新增的任何清理函式仍將被呼叫。

在 3.1 版本中新增。

enterContext(cm)

進入提供的 上下文管理器。如果成功,還會透過 addCleanup() 將其 __exit__() 方法新增為清理函式,並返回 __enter__() 方法的結果。

3.11 版本新增。

doCleanups()

此方法在 tearDown() 之後或在 setUp() 引發異常後無條件呼叫。

它負責呼叫由 addCleanup() 新增的所有清理函式。如果您需要清理函式在 tearDown() 之前 呼叫,那麼您可以自己呼叫 doCleanups()

doCleanups() 逐個彈出清理函式堆疊中的方法,因此可以隨時呼叫。

在 3.1 版本中新增。

classmethod addClassCleanup(function, /, *args, **kwargs)

新增一個函式,在 tearDownClass() 之後呼叫,以清理測試類期間使用的資源。函式將按照它們新增的相反順序(後進先出 LIFO)呼叫。呼叫時,會將傳遞給 addClassCleanup() 的任何引數和關鍵字引數傳遞給它們。

如果 setUpClass() 失敗,這意味著不會呼叫 tearDownClass(),那麼新增的任何清理函式仍將被呼叫。

3.8 版本新增。

classmethod enterClassContext(cm)

進入提供的 上下文管理器。如果成功,還會透過 addClassCleanup() 將其 __exit__() 方法新增為清理函式,並返回 __enter__() 方法的結果。

3.11 版本新增。

classmethod doClassCleanups()

此方法在 tearDownClass() 之後或在 setUpClass() 引發異常後無條件呼叫。

它負責呼叫所有由 addClassCleanup() 新增的清理函式。 如果您需要在 tearDownClass() 之前 呼叫清理函式,那麼您可以自己呼叫 doClassCleanups()

doClassCleanups() 每次從清理函式堆疊中彈出一個方法,因此可以隨時呼叫它。

3.8 版本新增。

class unittest.IsolatedAsyncioTestCase(methodName='runTest')

此類提供類似於 TestCase 的 API,並且還接受協程作為測試函式。

3.8 版本新增。

loop_factory

傳遞給 asyncio.Runnerloop_factory。在子類中使用 asyncio.EventLoop 覆蓋,以避免使用 asyncio 策略系統。

在 3.13 版本中新增。

coroutine asyncSetUp()

呼叫此方法來準備測試夾具。它在 setUp() 之後呼叫。它在呼叫測試方法之前立即呼叫;除了 AssertionErrorSkipTest 之外,此方法引發的任何異常都將被視為錯誤而不是測試失敗。預設實現不執行任何操作。

coroutine asyncTearDown()

在測試方法被呼叫且結果被記錄後立即呼叫的方法。它在 tearDown() 之前呼叫。即使測試方法引發了異常也會呼叫此方法,因此子類中的實現可能需要特別小心地檢查內部狀態。此方法引發的任何異常,除了 AssertionErrorSkipTest 之外,都將被視為額外的錯誤,而不是測試失敗(從而增加報告的錯誤總數)。只有在 asyncSetUp() 成功時才會呼叫此方法,無論測試方法的結果如何。預設實現不執行任何操作。

addAsyncCleanup(function, /, *args, **kwargs)

此方法接受可用作清理函式的協程。

coroutine enterAsyncContext(cm)

進入提供的非同步上下文管理器。如果成功,還會透過 addAsyncCleanup() 將其 __aexit__() 方法新增為清理函式,並返回 __aenter__() 方法的結果。

3.11 版本新增。

run(result=None)

設定一個新的事件迴圈來執行測試,將結果收集到作為 result 傳遞的 TestResult 物件中。如果省略 resultresultNone,則會建立一個臨時結果物件(透過呼叫 defaultTestResult() 方法)並使用。結果物件將返回給 run() 的呼叫者。在測試結束時,事件迴圈中的所有任務都將被取消。

一個說明順序的示例

from unittest import IsolatedAsyncioTestCase

events = []


class Test(IsolatedAsyncioTestCase):


    def setUp(self):
        events.append("setUp")

    async def asyncSetUp(self):
        self._async_connection = await AsyncConnection()
        events.append("asyncSetUp")

    async def test_response(self):
        events.append("test_response")
        response = await self._async_connection.get("https://example.com")
        self.assertEqual(response.status_code, 200)
        self.addAsyncCleanup(self.on_cleanup)

    def tearDown(self):
        events.append("tearDown")

    async def asyncTearDown(self):
        await self._async_connection.close()
        events.append("asyncTearDown")

    async def on_cleanup(self):
        events.append("cleanup")

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

執行測試後,events 將包含 ["setUp", "asyncSetUp", "test_response", "asyncTearDown", "tearDown", "cleanup"]

class unittest.FunctionTestCase(testFunc, setUp=None, tearDown=None, description=None)

此類實現了 TestCase 介面的一部分,該介面允許測試執行器驅動測試,但不提供測試程式碼可用於檢查和報告錯誤的方法。這用於建立使用遺留測試程式碼的測試用例,使其可以整合到基於 unittest 的測試框架中。

分組測試

class unittest.TestSuite(tests=())

此類表示單個測試用例和測試套件的聚合。此類提供測試執行器所需的介面,以允許其像任何其他測試用例一樣執行。執行 TestSuite 例項與迭代套件並單獨執行每個測試相同。

如果給定 tests,它必須是一個由單個測試用例或其他測試套件組成的可迭代物件,這些物件將用於最初構建套件。還提供了其他方法來稍後向集合中新增測試用例和套件。

TestSuite 物件行為很像 TestCase 物件,但它們實際上並不實現測試。相反,它們用於將測試聚合到應一起執行的測試組中。一些其他方法可用於向 TestSuite 例項新增測試

addTest(test)

TestCaseTestSuite 新增到套件。

addTests(tests)

將來自 TestCaseTestSuite 例項的可迭代物件中的所有測試新增到此測試套件。

這等效於迭代 tests,併為每個元素呼叫 addTest()

TestSuiteTestCase 共享以下方法

run(result)

執行與此套件關聯的測試,將結果收集到作為 result 傳遞的測試結果物件中。請注意,與 TestCase.run() 不同,TestSuite.run() 需要傳入結果物件。

debug()

執行與此套件關聯的測試,但不收集結果。這允許將測試引發的異常傳播給呼叫者,並且可用於支援在偵錯程式下執行測試。

countTestCases()

返回此測試物件表示的測試數量,包括所有單獨的測試和子套件。

__iter__()

TestSuite 分組的測試始終透過迭代訪問。子類可以透過覆蓋 __iter__() 來延遲提供測試。請注意,此方法可能會在單個套件上多次呼叫(例如,在計數測試或比較相等性時),因此在 TestSuite.run() 之前重複迭代返回的測試必須每次呼叫迭代都相同。在 TestSuite.run() 之後,除非呼叫者使用覆蓋 TestSuite._removeTestAtIndex() 來保留測試引用的子類,否則呼叫者不應依賴此方法返回的測試。

在 3.2 版本中變更: 在早期版本中,TestSuite 直接訪問測試而不是透過迭代,因此覆蓋 __iter__() 不足以提供測試。

在 3.4 版本中變更: 在早期版本中,TestSuiteTestSuite.run() 之後保留對每個 TestCase 的引用。子類可以透過覆蓋 TestSuite._removeTestAtIndex() 來恢復該行為。

TestSuite 物件的典型用法中,run() 方法由 TestRunner 而不是終端使用者測試工具呼叫。

載入和執行測試

class unittest.TestLoader

TestLoader 類用於從類和模組建立測試套件。通常,無需建立此類的例項;unittest 模組提供了一個可以共享的例項,即 unittest.defaultTestLoader。 但是,使用子類或例項可以自定義某些可配置的屬性。

TestLoader 物件具有以下屬性

errors

載入測試時遇到的非致命錯誤列表。載入器在任何時候都不會重置此列表。致命錯誤透過相關方法向呼叫者引發異常來發出訊號。非致命錯誤也由一個合成測試指示,該測試在執行時將引發原始錯誤。

3.5 版本新增。

TestLoader 物件具有以下方法

loadTestsFromTestCase(testCaseClass)

返回 TestCase 派生的 testCaseClass 中包含的所有測試用例的套件。

getTestCaseNames() 命名的每個方法建立一個測試用例例項。 預設情況下,這些是以 test 開頭的方法名稱。 如果 getTestCaseNames() 沒有返回任何方法,但實現了 runTest() 方法,則會為該方法建立一個測試用例。

loadTestsFromModule(module, *, pattern=None)

返回給定模組中包含的所有測試用例的套件。此方法在 module 中搜索從 TestCase 派生的類,併為該類定義的每個測試方法建立該類的一個例項。

註解

雖然使用 TestCase 派生類的層次結構可以方便地共享 fixtures 和輔助函式,但在不打算直接例項化的基類上定義測試方法並不適用於此方法。但是,當 fixtures 不同且在子類中定義時,這樣做可能很有用。

如果模組提供了 load_tests 函式,則將呼叫該函式來載入測試。這允許模組自定義測試載入。這是load_tests 協議pattern 引數作為第三個引數傳遞給 load_tests

在 3.2 版本中變更: 添加了對 load_tests 的支援。

在 3.5 版本中變更: 已新增對僅關鍵字引數 pattern 的支援。

在 3.12 版本中變更: 已刪除未記錄和非官方的 use_load_tests 引數。

loadTestsFromName(name, module=None)

返回給定字串說明符的所有測試用例的套件。

說明符 name 是一個“點式名稱”,可以解析為模組、測試用例類、測試用例類中的測試方法、TestSuite 例項,或返回 TestCaseTestSuite 例項的可呼叫物件。 這些檢查按照此處列出的順序應用;也就是說,一個可能的測試用例類上的方法將被視為“測試用例類中的測試方法”,而不是“可呼叫物件”。

例如,如果您有一個模組 SampleTests,其中包含一個 TestCase 派生的類 SampleTestCase,其中包含三個測試方法(test_one()test_two()test_three()),說明符 'SampleTests.SampleTestCase' 將導致此方法返回一個將執行所有三個測試方法的套件。 使用說明符 'SampleTests.SampleTestCase.test_two' 將導致它返回一個僅執行 test_two() 測試方法的測試套件。 說明符可以引用尚未匯入的模組和包;它們將作為副作用匯入。

該方法可以選擇相對於給定的模組解析名稱

在 3.5 版本中變更: 如果在遍歷 name 時發生 ImportErrorAttributeError,則將返回一個合成測試,該測試在執行時會引發該錯誤。 這些錯誤會包含在 self.errors 累積的錯誤中。

loadTestsFromNames(names, module=None)

類似於 loadTestsFromName(),但接受的是名稱序列而不是單個名稱。返回值是一個測試套件,它支援為每個名稱定義的所有測試。

getTestCaseNames(testCaseClass)

返回在 testCaseClass 中找到的排序後的方法名稱序列;這應該是 TestCase 的子類。

discover(start_dir, pattern='test*.py', top_level_dir=None)

透過從指定的起始目錄遞迴進入子目錄來查詢所有測試模組,並返回一個包含它們的 TestSuite 物件。只會載入與 pattern 匹配的測試檔案。(使用 shell 樣式模式匹配。)只會載入可匯入的模組名稱(即有效的 Python 識別符號)。

所有測試模組都必須可以從專案的頂層匯入。如果起始目錄不是頂層目錄,則必須單獨指定 top_level_dir

如果匯入模組失敗,例如由於語法錯誤,則會將其記錄為單個錯誤,並且發現將繼續。如果匯入失敗是由於引發了 SkipTest,則會將其記錄為跳過而不是錯誤。

如果找到一個包(包含名為 __init__.py 的檔案的目錄),則會檢查該包中是否存在 load_tests 函式。如果存在此函式,則將呼叫 package.load_tests(loader, tests, pattern)。測試發現會注意確保在一次呼叫期間僅對包檢查一次測試,即使 load_tests 函式本身呼叫 loader.discover

如果 load_tests 存在,則發現不會遞迴進入包,load_tests 負責載入包中的所有測試。

該模式被特意不儲存為載入器屬性,以便包可以繼續自行發現。

top_level_dir 在內部儲存,並用作對 discover() 的任何巢狀呼叫的預設值。也就是說,如果包的 load_tests 呼叫 loader.discover(),則不需要傳遞此引數。

start_dir 可以是虛線模組名稱以及目錄。

在 3.2 版本中新增。

在 3.4 版本中變更: 匯入時引發 SkipTest 的模組會記錄為跳過,而不是錯誤。

在 3.4 版本中變更: start_dir 可以是 名稱空間包

在 3.4 版本中變更: 路徑在匯入之前進行排序,以便即使底層檔案系統的順序不依賴於檔名,執行順序也相同。

在 3.5 版本中變更: 現在,無論找到的包的路徑是否與 pattern 匹配,都會檢查這些包是否存在 load_tests,因為包名稱不可能與預設模式匹配。

在 3.11 版本中變更: start_dir 不能是 名稱空間包。自 Python 3.7 以來,它已被破壞,Python 3.11 正式將其刪除。

在 3.13 版本中變更: top_level_dir 僅在 discover 呼叫的持續時間記憶體儲。

TestLoader 的以下屬性可以透過子類化或在例項上賦值來配置

testMethodPrefix

字串,給出將被解釋為測試方法的方法名稱的字首。預設值為 'test'

這會影響 getTestCaseNames() 和所有 loadTestsFrom* 方法。

sortTestMethodsUsing

getTestCaseNames() 和所有 loadTestsFrom* 方法中排序方法名稱時要使用的比較函式。

suiteClass

可呼叫物件,用於從測試列表中構造測試套件。不需要結果物件上的任何方法。預設值是 TestSuite 類。

這會影響所有 loadTestsFrom* 方法。

testNamePatterns

Unix shell 樣式萬用字元測試名稱模式列表,測試方法必須匹配這些模式才能包含在測試套件中(請參見 -k 選項)。

如果此屬性不是 None(預設值),則要包含在測試套件中的所有測試方法都必須匹配此列表中的一個模式。請注意,匹配始終使用 fnmatch.fnmatchcase() 執行,因此與傳遞給 -k 選項的模式不同,簡單的子字串模式必須使用 * 萬用字元進行轉換。

這會影響所有 loadTestsFrom* 方法。

3.7 版本新增。

class unittest.TestResult

此類用於編譯有關哪些測試成功和哪些測試失敗的資訊。

TestResult 物件儲存一組測試的結果。TestCaseTestSuite 類確保正確記錄結果;測試編寫者無需擔心記錄測試的結果。

構建在 unittest 之上的測試框架可能需要訪問透過執行一組測試生成的 TestResult 物件以進行報告;為此目的,TestRunner.run() 方法返回一個 TestResult 例項。

TestResult 例項具有以下屬性,這些屬性在檢查執行一組測試的結果時會很有用

errors

一個列表,包含 TestCase 例項和包含格式化回溯的字串的 2 元組。每個元組表示引發意外異常的測試。

failures

一個列表,包含 TestCase 例項和包含格式化回溯的字串的 2 元組。每個元組表示使用 assert* 方法 明確發出失敗訊號的測試。

skipped

一個列表,其中包含 TestCase 例項的 2 元組以及儲存跳過測試原因的字串。

在 3.1 版本中新增。

expectedFailures

一個列表,其中包含 TestCase 例項和儲存格式化回溯的字串的 2 元組。每個元組表示測試用例的預期失敗或錯誤。

unexpectedSuccesses

一個列表,其中包含被標記為預期失敗但卻成功的 TestCase 例項。

collectedDurations

一個列表,其中包含測試用例名稱和浮點數的 2 元組,表示每個執行的測試的經過時間。

在 3.12 版本中新增。

shouldStop

當測試執行應該被 stop() 停止時,設定為 True

testsRun

到目前為止執行的測試總數。

buffer

如果設定為 true,則在 startTest()stopTest() 被呼叫之間,sys.stdoutsys.stderr 將被緩衝。只有當測試失敗或出錯時,收集到的輸出才會回顯到真實的 sys.stdoutsys.stderr。任何輸出也會附加到失敗/錯誤訊息中。

在 3.2 版本中新增。

failfast

如果設定為 true,則在第一次失敗或錯誤時將呼叫 stop(),從而停止測試執行。

在 3.2 版本中新增。

tb_locals

如果設定為 true,則區域性變數將顯示在回溯中。

3.5 版本新增。

wasSuccessful()

如果到目前為止執行的所有測試都通過了,則返回 True,否則返回 False

在 3.4 版本中更改:如果來自使用 expectedFailure() 裝飾器標記的測試中存在任何 unexpectedSuccesses,則返回 False

stop()

可以呼叫此方法來發出訊號,表明應透過將 shouldStop 屬性設定為 True 來中止正在執行的測試集。 TestRunner 物件應遵守此標誌,並在不執行任何其他測試的情況下返回。

例如,當用戶從鍵盤發出中斷訊號時,TextTestRunner 類使用此功能來停止測試框架。提供 TestRunner 實現的互動式工具可以以類似的方式使用它。

TestResult 類的以下方法用於維護內部資料結構,並且可以在子類中擴充套件以支援其他報告要求。這在構建在測試執行時支援互動式報告的工具中特別有用。

startTest(test)

當測試用例 test 即將執行時呼叫。

stopTest(test)

在測試用例 test 執行完畢後呼叫,無論結果如何。

startTestRun()

在執行任何測試之前呼叫一次。

在 3.1 版本中新增。

stopTestRun()

在所有測試執行完畢後呼叫一次。

在 3.1 版本中新增。

addError(test, err)

當測試用例 test 引發意外異常時呼叫。err 是由 sys.exc_info() 返回的形式的元組: (type, value, traceback)

預設實現將元組 (test, formatted_err) 附加到例項的 errors 屬性,其中 formatted_err 是從 err 匯出的格式化回溯。

addFailure(test, err)

當測試用例 test 發出失敗訊號時呼叫。err 是由 sys.exc_info() 返回的形式的元組: (type, value, traceback)

預設實現將元組 (test, formatted_err) 附加到例項的 failures 屬性,其中 formatted_err 是從 err 匯出的格式化回溯。

addSuccess(test)

當測試用例 test 成功時呼叫。

預設實現不執行任何操作。

addSkip(test, reason)

當測試用例 test 被跳過時呼叫。reason 是測試跳過的原因。

預設實現將元組 (test, reason) 附加到例項的 skipped 屬性。

addExpectedFailure(test, err)

當測試用例 test 失敗或出錯,但使用 expectedFailure() 裝飾器標記時呼叫。

預設實現將元組 (test, formatted_err) 附加到例項的 expectedFailures 屬性,其中 formatted_err 是從 err 匯出的格式化回溯。

addUnexpectedSuccess(test)

當測試用例 test 使用 expectedFailure() 裝飾器標記,但成功時呼叫。

預設實現將測試附加到例項的 unexpectedSuccesses 屬性。

addSubTest(test, subtest, outcome)

當子測試完成時呼叫。test 是對應於測試方法的測試用例。subtest 是一個自定義的 TestCase 例項,描述子測試。

如果 outcomeNone,則子測試成功。否則,子測試失敗,並丟擲一個異常,其中 outcome 是由 sys.exc_info() 返回的以下形式的元組:(type, value, traceback)

預設實現會在結果成功時不執行任何操作,並將子測試失敗記錄為普通失敗。

在 3.4 版本中新增。

addDuration(test, elapsed)

在測試用例完成時呼叫。elapsed 是以秒為單位表示的時間,包括清理函式的執行時間。

在 3.12 版本中新增。

class unittest.TextTestResult(stream, descriptions, verbosity, *, durations=None)

TextTestRunner 使用的 TestResult 的具體實現。子類應接受 **kwargs 以確保在介面更改時的相容性。

在 3.2 版本中新增。

3.12 版本中的更改: 添加了 durations 關鍵字引數。

unittest.defaultTestLoader

旨在共享的 TestLoader 類的例項。如果不需要對 TestLoader 進行自定義,可以使用此例項,而無需重複建立新例項。

class unittest.TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, buffer=False, resultclass=None, warnings=None, *, tb_locals=False, durations=None)

一個基本的測試執行器實現,將結果輸出到流。如果 streamNone(預設值),則使用 sys.stderr 作為輸出流。此類有一些可配置的引數,但本質上非常簡單。執行測試套件的圖形應用程式應提供替代實現。當 unittest 新增功能時,此類實現應接受 **kwargs 作為構造執行器的介面。

預設情況下,此執行器顯示 DeprecationWarningPendingDeprecationWarningResourceWarningImportWarning,即使它們是 預設被忽略的。可以使用 Python 的 -Wd-Wa 選項(請參閱 警告控制)並將 warnings 保留為 None 來覆蓋此行為。

3.2 版本中的更改: 添加了 warnings 引數。

3.2 版本中的更改: 預設流在例項化時而不是在匯入時設定為 sys.stderr

3.5 版本中的更改: 添加了 tb_locals 引數。

3.12 版本中的更改: 添加了 durations 引數。

_makeResult()

此方法返回 run() 使用的 TestResult 的例項。它不打算直接呼叫,但可以在子類中重寫以提供自定義的 TestResult

_makeResult() 例項化在 TextTestRunner 建構函式中作為 resultclass 引數傳入的類或可呼叫物件。如果沒有提供 resultclass,則預設為 TextTestResult。結果類使用以下引數例項化

stream, descriptions, verbosity
run(test)

此方法是 TextTestRunner 的主要公共介面。此方法接受 TestSuiteTestCase 例項。透過呼叫 _makeResult() 建立一個 TestResult,並執行測試並將結果列印到 stdout。

unittest.main(module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=unittest.defaultTestLoader, exit=True, verbosity=1, failfast=None, catchbreak=None, buffer=None, warnings=None)

一個命令列程式,從 module 載入一組測試並執行它們;這主要是為了使測試模組方便地執行。此函式最簡單的用法是在測試指令碼的末尾包含以下行

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

您可以透過傳入 verbosity 引數來執行具有更詳細資訊的測試

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

defaultTest 引數是單個測試的名稱或要執行的測試名稱的可迭代物件(如果未透過 argv 指定測試名稱)。如果未指定或為 None,並且未透過 argv 提供測試名稱,則將執行 module 中找到的所有測試。

argv 引數可以是傳遞給程式的選項列表,其中第一個元素是程式名稱。如果未指定或為 None,則使用 sys.argv 的值。

testRunner 引數可以是測試執行器類,也可以是其已建立的例項。預設情況下,main 會呼叫 sys.exit(),並使用退出程式碼指示執行的測試是成功 (0) 還是失敗 (1)。退出程式碼為 5 表示沒有執行任何測試或跳過了測試。

testLoader 引數必須是 TestLoader 的例項,預設值為 defaultTestLoader

透過傳入引數 exit=False,可以在互動式直譯器中使用 main。這會在標準輸出上顯示結果,而不會呼叫 sys.exit()

>>> from unittest import main
>>> main(module='test_module', exit=False)

failfastcatchbreakbuffer 引數的效果與同名的 命令列選項相同。

warnings 引數指定執行測試時應使用的警告過濾器。如果未指定,則當向 python 傳遞 -W 選項時,它將保持為 None (請參閱警告控制),否則它將設定為 'default'

呼叫 main 會返回一個物件,該物件的 result 屬性包含以 unittest.TestResult 形式執行的測試結果。

在 3.1 版本中更改:添加了 exit 引數。

在 3.2 版本中更改:添加了 verbosityfailfastcatchbreakbufferwarnings 引數。

在 3.4 版本中更改:defaultTest 引數已更改為也接受測試名稱的可迭代物件。

load_tests 協議

在 3.2 版本中新增。

模組或包可以透過實現一個名為 load_tests 的函式來自定義在正常測試執行或測試發現期間如何從中載入測試。

如果測試模組定義了 load_tests,則 TestLoader.loadTestsFromModule() 將使用以下引數呼叫它

load_tests(loader, standard_tests, pattern)

其中 pattern 是直接從 loadTestsFromModule 傳遞的。它預設為 None

它應該返回一個 TestSuite

loader 是執行載入的 TestLoader 的例項。standard_tests 是預設情況下將從模組載入的測試。測試模組通常只希望從標準測試集中新增或刪除測試。第三個引數用於在測試發現中載入包。

一個典型的從一組特定的 TestCase 類載入測試的 load_tests 函式可能如下所示

test_cases = (TestCase1, TestCase2, TestCase3)

def load_tests(loader, tests, pattern):
    suite = TestSuite()
    for test_class in test_cases:
        tests = loader.loadTestsFromTestCase(test_class)
        suite.addTests(tests)
    return suite

如果從命令列或透過呼叫 TestLoader.discover() 在包含包的目錄中啟動發現,則將檢查包 __init__.py 是否存在 load_tests。如果該函式不存在,則發現將像遞迴到另一個目錄一樣遞迴到包中。否則,將由 load_tests 來進行包的測試發現,該函式將使用以下引數呼叫

load_tests(loader, standard_tests, pattern)

這應該返回一個表示包中所有測試的 TestSuite。(standard_tests 只會包含從 __init__.py 收集的測試。)

因為模式被傳遞到 load_tests 中,所以包可以自由地繼續(並可能修改)測試發現。一個“不做任何事”的測試包的 load_tests 函式如下所示

def load_tests(loader, standard_tests, pattern):
    # top level directory cached on loader instance
    this_dir = os.path.dirname(__file__)
    package_tests = loader.discover(start_dir=this_dir, pattern=pattern)
    standard_tests.addTests(package_tests)
    return standard_tests

在 3.5 版本中更改:由於包名稱不可能與預設模式匹配,因此發現不再檢查與 pattern 匹配的包名稱。

類和模組固定裝置

類和模組級別的固定裝置在 TestSuite 中實現。當測試套件遇到來自新類的測試時,會呼叫前一個類的 tearDownClass() (如果存在),然後呼叫新類的 setUpClass()

類似地,如果測試來自與前一個測試不同的模組,則會執行前一個模組的 tearDownModule,然後執行新模組的 setUpModule

在所有測試都執行完畢後,會執行最終的 tearDownClasstearDownModule

請注意,共享固定裝置與測試並行化等[潛在]功能不相容,並且會破壞測試隔離。應謹慎使用它們。

unittest 測試載入器建立的測試的預設順序是將來自同一模組和類的所有測試分組在一起。這將導致每個類和模組的 setUpClass / setUpModule (等) 函式只調用一次。如果將順序隨機化,使來自不同模組和類的測試彼此相鄰,那麼這些共享固定裝置函式可能會在單個測試執行中被多次呼叫。

共享固定裝置不適用於具有非標準排序的套件。BaseTestSuite 仍然存在於不希望支援共享固定裝置的框架中。

如果在其中一個共享固定裝置函式中引發了任何異常,則該測試將報告為錯誤。由於沒有相應的測試例項,因此會建立一個 _ErrorHolder 物件 (該物件具有與 TestCase 相同的介面) 來表示錯誤。如果您只是使用標準的 unittest 測試執行器,那麼這個細節並不重要,但如果您是框架作者,它可能很重要。

setUpClass 和 tearDownClass

它們必須實現為類方法

import unittest

class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls._connection = createExpensiveConnectionObject()

    @classmethod
    def tearDownClass(cls):
        cls._connection.destroy()

如果您希望呼叫基類上的 setUpClasstearDownClass,則必須自己呼叫它們。TestCase 中的實現為空。

如果在 setUpClass 期間引發了異常,則不會執行類中的測試,也不會執行 tearDownClass。跳過的類將不會執行 setUpClasstearDownClass。如果異常是 SkipTest 異常,則該類將被報告為已跳過,而不是作為錯誤。

setUpModule 和 tearDownModule

它們應實現為函式

def setUpModule():
    createConnection()

def tearDownModule():
    closeConnection()

如果在 setUpModule 中引發了異常,則不會執行模組中的任何測試,也不會執行 tearDownModule。如果異常是 SkipTest 異常,則該模組將被報告為已跳過,而不是作為錯誤。

要新增即使在出現異常的情況下也必須執行的清理程式碼,請使用 addModuleCleanup

unittest.addModuleCleanup(function, /, *args, **kwargs)

新增一個函式,該函式將在 tearDownModule() 之後呼叫,以清理測試類期間使用的資源。 函式將按照新增順序的反向順序(LIFO)呼叫。當它們被新增時,會使用傳遞給 addModuleCleanup() 的任何引數和關鍵字引數來呼叫它們。

如果 setUpModule() 失敗,意味著不會呼叫 tearDownModule(),那麼任何新增的清理函式仍然會被呼叫。

3.8 版本新增。

classmethod unittest.enterModuleContext(cm)

進入提供的上下文管理器。如果成功,還會透過 addModuleCleanup() 將其 __exit__() 方法新增為清理函式,並返回 __enter__() 方法的結果。

3.11 版本新增。

unittest.doModuleCleanups()

此函式在 tearDownModule() 之後無條件呼叫,或者在 setUpModule() 丟擲異常後呼叫。

它負責呼叫所有由 addModuleCleanup() 新增的清理函式。如果您需要在 tearDownModule() 之前 呼叫清理函式,那麼您可以自己呼叫 doModuleCleanups()

doModuleCleanups() 從清理函式堆疊中一次彈出一個方法,因此可以在任何時候呼叫。

3.8 版本新增。

訊號處理

在 3.2 版本中新增。

unittest 的 -c/--catch 命令列選項,以及 unittest.main()catchbreak 引數,在測試執行期間提供了更友好的 control-C 處理。啟用捕獲中斷行為後,control-C 將允許當前正在執行的測試完成,然後測試執行將結束並報告到目前為止的所有結果。第二次 control-c 將以通常的方式引發 KeyboardInterrupt

control-c 處理訊號處理程式嘗試與安裝了自己的 signal.SIGINT 處理程式的程式碼或測試保持相容。如果呼叫了 unittest 處理程式,但它不是已安裝的 signal.SIGINT 處理程式,即它已被被測系統替換並委託,那麼它會呼叫預設處理程式。這通常是替換已安裝的處理程式並委託給它的程式碼所期望的行為。對於需要停用 unittest control-c 處理的單個測試,可以使用 removeHandler() 裝飾器。

有一些實用函式供框架作者在測試框架中啟用 control-c 處理功能。

unittest.installHandler()

安裝 control-c 處理程式。當收到 signal.SIGINT 時(通常是響應使用者按下 control-c),所有已註冊的結果都會呼叫 stop()

unittest.registerResult(result)

註冊一個用於 control-c 處理的 TestResult 物件。註冊結果會儲存對它的弱引用,因此它不會阻止結果被垃圾回收。

如果未啟用 control-c 處理,註冊 TestResult 物件沒有副作用,因此測試框架可以無條件地註冊它們建立的所有結果,而無需考慮是否啟用了處理。

unittest.removeResult(result)

刪除已註冊的結果。一旦刪除結果,那麼在響應 control-c 時,將不再在該結果物件上呼叫 stop()

unittest.removeHandler(function=None)

在不帶引數的情況下呼叫此函式會刪除已安裝的 control-c 處理程式。此函式也可以用作測試裝飾器,以便在執行測試時臨時刪除處理程式

@unittest.removeHandler
def test_signal_handling(self):
    ...