unittest --- 單元測試框架?

源代碼: Lib/unittest/__init__.py


(如果你已經(jīng)對測試的概念比較熟悉了,你可能想直接跳轉到這一部分 斷言方法。)

unittest 單元測試框架是受到 JUnit 的啟發(fā),與其他語(yǔ)言中的主流單元測試框架有著(zhù)相似的風(fēng)格。其支持測試自動(dòng)化,配置共享和關(guān)機代碼測試。支持將測試樣例聚合到測試集中,并將測試與報告框架獨立。

為了實(shí)現這些,unittest 通過(guò)面向對象的方式支持了一些重要的概念。

測試腳手架

test fixture 表示為了開(kāi)展一項或多項測試所需要進(jìn)行的準備工作,以及所有相關(guān)的清理操作。舉個(gè)例子,這可能包含創(chuàng )建臨時(shí)或代理的數據庫、目錄,再或者啟動(dòng)一個(gè)服務(wù)器進(jìn)程。

測試用例

一個(gè)測試用例是一個(gè)獨立的測試單元。它檢查輸入特定的數據時(shí)的響應。 unittest 提供一個(gè)基類(lèi): TestCase ,用于新建測試用例。

測試套件

test suite 是一系列的測試用例,或測試套件,或兩者皆有。它用于歸檔需要一起執行的測試。

測試運行器(test runner)

test runner 是一個(gè)用于執行和輸出測試結果的組件。這個(gè)運行器可能使用圖形接口、文本接口,或返回一個(gè)特定的值表示運行測試的結果。

參見(jiàn)

doctest --- 文檔測試模塊

另一個(gè)風(fēng)格完全不同的測試模塊。

簡(jiǎn)單 Smalltalk 測試:便用模式

Kent Beck 有關(guān)使用 unittest 所共享的模式的測試框架的原創(chuàng )論文。

pytest

第三方單元測試框架,提供輕量化的語(yǔ)法來(lái)編寫(xiě)測試,例如:assert func(10) == 42。

Python 測試工具分類(lèi)

一個(gè) Python 測試工具的詳細列表,包含測試框架和模擬對象庫。

Python 中的測試 郵件列表

一個(gè)討論 Python 中的測試和測試工具的特別興趣小組。

The script Tools/unittestgui/unittestgui.py in the Python source distribution is a GUI tool for test discovery and execution. This is intended largely for ease of use for those new to unit testing. For production environments it is recommended that tests be driven by a continuous integration system such as Buildbot, Jenkins, GitHub Actions, or AppVeyor.

基本實(shí)例?

unittest 模塊提供了一系列創(chuàng )建和運行測試的工具。這一段落演示了這些工具的一小部分,但也足以滿(mǎn)足大部分用戶(hù)的需求。

這是一段簡(jiǎn)短的代碼,來(lái)測試三種字符串方法:

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 就創(chuàng )建了一個(gè)測試樣例。上述三個(gè)獨立的測試是三個(gè)類(lèi)的方法,這些方法的命名都以 test 開(kāi)頭。 這個(gè)命名約定告訴測試運行者類(lèi)的哪些方法表示測試。

每個(gè)測試的關(guān)鍵是:調用 assertEqual() 來(lái)檢查預期的輸出; 調用 assertTrue()assertFalse() 來(lái)驗證一個(gè)條件;調用 assertRaises() 來(lái)驗證拋出了一個(gè)特定的異常。使用這些方法而不是 assert 語(yǔ)句是為了讓測試運行者能聚合所有的測試結果并產(chǎn)生結果報告。

通過(guò) setUp()tearDown() 方法,可以設置測試開(kāi)始前與完成后需要執行的指令。 在 組織你的測試代碼 中,對此有更為詳細的描述。

最后的代碼塊中,演示了運行測試的一個(gè)簡(jiǎn)單的方法。 unittest.main() 提供了一個(gè)測試腳本的命令行接口。當在命令行運行該測試腳本,上文的腳本生成如以下格式的輸出:

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

OK

在調用測試腳本時(shí)添加 -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 中最常用的、足夠滿(mǎn)足許多日常測試需求的特性。文檔的剩余部分詳述該框架的完整特性。

在 3.11 版更改: The behavior of returning a value from a test method (other than the default None value), is now deprecated.

命令行接口?

unittest 模塊可以通過(guò)命令行運行模塊、類(lèi)和獨立測試方法的測試:

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

你可以傳入模塊名、類(lèi)或方法名或他們的任意組合。

同樣的,測試模塊可以通過(guò)文件路徑指定:

python -m unittest tests/test_something.py

這樣就可以使用 shell 的文件名補全指定測試模塊。所指定的文件仍需要可以被作為模塊導入。路徑通過(guò)去除 '.py' 、把分隔符轉換為 '.' 轉換為模塊名。若你需要執行不能被作為模塊導入的測試文件,你需要直接執行該測試文件。

在運行測試時(shí),你可以通過(guò)添加 -v 參數獲取更詳細(更多的冗余)的信息。

python -m unittest -v test_module

當運行時(shí)不包含參數,開(kāi)始 探索性測試

python -m unittest

用于獲取命令行選項列表:

python -m unittest -h

在 3.2 版更改: 在早期版本中,只支持運行獨立的測試方法,而不支持模塊和類(lèi)。

命令行選項?

unittest supports these command-line options:

-b, --buffer?

在測試運行時(shí),標準輸出流與標準錯誤流會(huì )被放入緩沖區。成功的測試的運行時(shí)輸出會(huì )被丟棄;測試不通過(guò)時(shí),測試運行中的輸出會(huì )正常顯示,錯誤會(huì )被加入到測試失敗信息。

-c, --catch?

當測試正在運行時(shí), Control-C 會(huì )等待當前測試完成,并在完成后報告已執行的測試的結果。當再次按下 Control-C 時(shí),引發(fā)平常的 KeyboardInterrupt 異常。

See Signal Handling for the functions that provide this functionality.

-f, --failfast?

當出現第一個(gè)錯誤或者失敗時(shí),停止運行測試。

-k?

Only run test methods and classes that match the pattern or substring. This option may be used multiple times, in which case all test cases that match any of the given patterns are included.

包含通配符(*)的模式使用 fnmatch.fnmatchcase() 對測試名稱(chēng)進(jìn)行匹配。另外,該匹配是大小寫(xiě)敏感的。

模式對測試加載器導入的測試方法全名進(jìn)行匹配。

例如,-k foo 可以匹配到 foo_tests.SomeTest.test_somethingbar_tests.SomeTest.test_foo ,但是不能匹配到 bar_tests.FooTest.test_something 。

--locals?

在回溯中顯示局部變量。

3.2 新版功能: 添加命令行選項 -b, -c-f 。

3.5 新版功能: 命令行選項 --locals 。

3.7 新版功能: 命令行選項 -k 。

命令行亦可用于探索性測試,以運行一個(gè)項目的所有測試或其子集。

探索性測試?

3.2 新版功能.

Unittest supports simple test discovery. In order to be compatible with test discovery, all of the test files must be modules or packages importable from the top-level directory of the project (this means that their filenames must be valid identifiers).

探索性測試在 TestLoader.discover() 中實(shí)現,但也可以通過(guò)命令行使用。它在命令行中的基本用法如下:

cd project_directory
python -m unittest discover

備注

方便起見(jiàn), python -m unittestpython -m unittest discover 等價(jià)。如果你需要向探索性測試傳入參數,必須顯式地使用 discover 子命令。

discover 有以下選項:

-v, --verbose?

更詳細地輸出結果。

-s, --start-directory directory?

開(kāi)始進(jìn)行搜索的目錄(默認值為當前目錄 . )。

-p, --pattern pattern?

用于匹配測試文件的模式(默認為 test*.py )。

-t, --top-level-directory directory?

指定項目的最上層目錄(通常為開(kāi)始時(shí)所在目錄)。

-s ,-p-t 選項可以按順序作為位置參數傳入。以下兩條命令是等價(jià)的:

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

正如可以傳入路徑那樣,傳入一個(gè)包名作為起始目錄也是可行的,如 myproject.subpackage.test 。你提供的包名會(huì )被導入,它在文件系統中的位置會(huì )被作為起始目錄。

小心

探索性測試通過(guò)導入測試對測試進(jìn)行加載。在找到所有你指定的開(kāi)始目錄下的所有測試文件后,它把路徑轉換為包名并進(jìn)行導入。如 foo/bar/baz.py 會(huì )被導入為 foo.bar.baz 。

如果你有一個(gè)全局安裝的包,并嘗試對這個(gè)包的副本進(jìn)行探索性測試,可能會(huì )從錯誤的地方開(kāi)始導入。如果出現這種情況,測試會(huì )輸出警告并退出。

如果你使用包名而不是路徑作為開(kāi)始目錄,搜索時(shí)會(huì )假定它導入的是你想要的目錄,所以你不會(huì )收到警告。

測試模塊和包可以通過(guò) load_tests protocol 自定義測試的加載和搜索。

在 3.4 版更改: 測試發(fā)現支持初始目錄下的 命名空間包。注意你也需要指定頂層目錄(例如:python -m unittest discover -s root/namespace -t root)。

在 3.11 版更改: Python 3.11 dropped the namespace packages support. It has been broken since Python 3.7. Start directory and subdirectories containing tests must be regular package that have __init__.py file.

Directories containing start directory still can be a namespace package. In this case, you need to specify start directory as dotted package name, and target directory explicitly. For example:

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

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

組織你的測試代碼?

單元測試的構建單位是 test cases :獨立的、包含執行條件與正確性檢查的方案。在 unittest 中,測試用例表示為 unittest.TestCase 的實(shí)例。通過(guò)編寫(xiě) TestCase 的子類(lèi)或使用 FunctionTestCase 編寫(xiě)你自己的測試用例。

一個(gè) TestCase 實(shí)例的測試代碼必須是完全自含的,因此它可以獨立運行,或與其它任意組合任意數量的測試用例一起運行。

TestCase 的最簡(jiǎn)單的子類(lèi)需要實(shí)現一個(gè)測試方法(例如一個(gè)命名以 test 開(kāi)頭的方法)以執行特定的測試代碼:

import unittest

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

可以看到,為了進(jìn)行測試,我們使用了基類(lèi) TestCase 提供的其中一個(gè) assert*() 方法。若測試不通過(guò),將會(huì )引發(fā)一個(gè)帶有說(shuō)明信息的異常,并且 unittest 會(huì )將這個(gè)測試用例標記為測試不通過(guò)。任何其它類(lèi)型的異常將會(huì )被當做錯誤處理。

可能同時(shí)存在多個(gè)前置操作相同的測試,我們可以把測試的前置操作從測試代碼中拆解出來(lái),并實(shí)現測試前置方法 setUp() 。在運行測試時(shí),測試框架會(huì )自動(dòng)地為每個(gè)單獨測試調用前置方法。

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')

備注

多個(gè)測試運行的順序由內置字符串排序方法對測試名進(jìn)行排序的結果決定。

在測試運行時(shí),若 setUp() 方法引發(fā)異常,測試框架會(huì )認為測試發(fā)生了錯誤,因此測試方法不會(huì )被運行。

相似的,我們提供了一個(gè) tearDown() 方法在測試方法運行后進(jìn)行清理工作。

import unittest

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

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

setUp() 成功運行,無(wú)論測試方法是否成功,都會(huì )運行 tearDown() 。

這樣的一個(gè)測試代碼運行的環(huán)境被稱(chēng)為 test fixture 。一個(gè)新的 TestCase 實(shí)例作為一個(gè)測試腳手架,用于運行各個(gè)獨立的測試方法。在運行每個(gè)測試時(shí),setUp() 、tearDown()__init__() 會(huì )被調用一次。

推薦你根據用例所測試的功能將測試用 TestCase 分組。unittest 為此提供了 test suiteunittestTestSuite 類(lèi)是一個(gè)代表。通常情況下,調用 unittest.main() 就能正確地找到并執行這個(gè)模塊下所有用 TestCase 分組的測試。

然而,如果你需要自定義你的測試套件的話(huà),你可以參考以下方法組織你的測試:

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)有幾個(gè)優(yōu)勢。

  • 測試模塊可以從命令行被獨立調用。

  • 更容易在分發(fā)的代碼中剝離測試代碼。

  • 降低沒(méi)有好理由的情況下修改測試代碼以通過(guò)測試的誘惑。

  • 測試代碼應比被測試代碼更少地被修改。

  • 被測試代碼可以更容易地被重構。

  • 對用 C 語(yǔ)言寫(xiě)成的模塊無(wú)論如何都得單獨寫(xiě)成一個(gè)模塊,為什么不保持一致呢?

  • 如果測試策略發(fā)生了改變,沒(méi)有必要修改源代碼。

復用已有的測試代碼?

一些用戶(hù)希望直接使用 unittest 運行已有的測試代碼,而不需要把已有的每個(gè)測試函數轉化為一個(gè) TestCase 的子類(lèi)。

因此, unittest 提供 FunctionTestCase 類(lèi)。這個(gè) TestCase 的子類(lèi)可用于打包已有的測試函數,并支持設置前置與后置函數。

假定有一個(gè)測試函數:

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

可以創(chuàng )建等價(jià)的測試用例如下,其中前置和后置方法是可選的。

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

備注

FunctionTestCase 可以快速將現有的測試轉換成基于 unittest 的測試,但不推薦你這樣做?;c(diǎn)時(shí)間繼承 TestCase 會(huì )讓以后重構測試無(wú)比輕松。

在某些情況下,現有的測試可能是用 doctest 模塊編寫(xiě)的。 如果是這樣, doctest 提供了一個(gè) DocTestSuite 類(lèi),可以從現有基于 doctest 的測試中自動(dòng)構建 unittest.TestSuite 用例。

跳過(guò)測試與預計的失敗?

3.1 新版功能.

Unittest 支持跳過(guò)單個(gè)或整組的測試用例。它還支持把測試標注成“預期失敗”的測試。這些壞測試會(huì )失敗,但不會(huì )算進(jìn) TestResult 的失敗里。

要跳過(guò)測試只需使用 skip() decorator 或其附帶條件的版本,在 setUp() 內部使用 TestCase.skipTest(),或是直接引發(fā) SkipTest。

跳過(guò)測試的基本用法如下:

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

在啰嗦模式下運行以上測試例子時(shí),程序輸出如下:

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)

跳過(guò)測試類(lèi)的寫(xiě)法跟跳過(guò)測試方法的寫(xiě)法相似:

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

TestCase.setUp() 也可以跳過(guò)測試??梢杂糜谒栀Y源不可用的情況下跳過(guò)接下來(lái)的測試。

使用 expectedFailure() 裝飾器表明這個(gè)測試預計失敗。:

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

你可以很容易地編寫(xiě)在測試時(shí)調用 skip() 的裝飾器作為自定義的跳過(guò)測試裝飾器。 下面這個(gè)裝飾器會(huì )跳過(guò)測試,除非所傳入的對象具有特定的屬性:

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

以下的裝飾器和異常實(shí)現了跳過(guò)測試和預期失敗兩種功能:

@unittest.skip(reason)?

跳過(guò)被此裝飾器裝飾的測試。 reason 為測試被跳過(guò)的原因。

@unittest.skipIf(condition, reason)?

condition 為真時(shí),跳過(guò)被裝飾的測試。

@unittest.skipUnless(condition, reason)?

跳過(guò)被裝飾的測試,除非 condition 為真。

@unittest.expectedFailure?

將測試標記為預期的失敗或錯誤。 如果測試失敗或在測試函數自身(而非在某個(gè) test fixture 方法)中出現錯誤則將認為是測試成功。 如果測試通過(guò),則將認為是測試失敗。

exception unittest.SkipTest(reason)?

引發(fā)此異常以跳過(guò)一個(gè)測試。

通常來(lái)說(shuō),你可以使用 TestCase.skipTest() 或其中一個(gè)跳過(guò)測試的裝飾器實(shí)現跳過(guò)測試的功能,而不是直接引發(fā)此異常。

被跳過(guò)的測試的 setUp()tearDown() 不會(huì )被運行。被跳過(guò)的類(lèi)的 setUpClass()tearDownClass() 不會(huì )被運行。被跳過(guò)的模組的 setUpModule()tearDownModule() 不會(huì )被運行。

使用子測試區分測試迭代?

3.4 新版功能.

當你的幾個(gè)測試之間的差異非常小,例如只有某些形參不同時(shí),unittest 允許你使用 subTest() 上下文管理器在一個(gè)測試方法體的內部區分它們。

例如,以下測試:

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

如果不使用子測試,程序遇到第一次錯誤之后就會(huì )停止。而且因為``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

類(lèi)與函數?

本節深入介紹了 unittest 的 API。

測試用例?

class unittest.TestCase(methodName='runTest')?

TestCase 類(lèi)的實(shí)例代表了 unittest 宇宙中的邏輯測試單元。 該類(lèi)旨在被當作基類(lèi)使用,特定的測試將由其實(shí)體子類(lèi)來(lái)實(shí)現。 該類(lèi)實(shí)現了測試運行器所需的接口以允許它驅動(dòng)測試,并實(shí)現了可被測試代碼用來(lái)檢測和報告各種類(lèi)型的失敗的方法。

每個(gè) TestCase 實(shí)例將運行一個(gè)單位的基礎方法:即名為 methodName 的方法。 在使用 TestCase 的大多數場(chǎng)景中,你都不需要修改 methodName 或重新實(shí)現默認的 runTest() 方法。

在 3.2 版更改: TestCase 不需要提供 methodName 即可成功實(shí)例化。 這使得從交互式解釋器試驗 TestCase 更為容易。

TestCase 的實(shí)例提供了三組方法:一組用來(lái)運行測試,另一組被測試實(shí)現用來(lái)檢查條件和報告失敗,還有一些查詢(xún)方法用來(lái)收集有關(guān)測試本身的信息。

第一組(用于運行測試的)方法是:

setUp()?

為測試預備而調用的方法。 此方法會(huì )在調用測試方法之前被調用;除了 AssertionErrorSkipTest,此方法所引發(fā)的任何異常都將被視為錯誤而非測試失敗。 默認的實(shí)現將不做任何事情。

tearDown()?

在測試方法被調用并記錄結果之后立即被調用的方法。 此方法即使在測試方法引發(fā)異常時(shí)仍會(huì )被調用,因此子類(lèi)中的實(shí)現將需要特別注意檢查內部狀態(tài)。 除 AssertionErrorSkipTest 外,此方法所引發(fā)的任何異常都將被視為額外的錯誤而非測試失?。ㄒ蚨鴷?huì )增加總計錯誤報告數)。 此方法將只在 setUp() 成功執行時(shí)被調用,無(wú)論測試方法的結果如何。 默認的實(shí)現將不做任何事情。

setUpClass()?

在一個(gè)單獨類(lèi)中的測試運行之前被調用的類(lèi)方法。 setUpClass 會(huì )被作為唯一的參數在類(lèi)上調用且必須使用 classmethod() 裝飾器:

@classmethod
def setUpClass(cls):
    ...

查看 Class and Module Fixtures 獲取更詳細的說(shuō)明。

3.2 新版功能.

tearDownClass()?

在一個(gè)單獨類(lèi)的測試完成運行之后被調用的類(lèi)方法。 tearDownClass 會(huì )被作為唯一的參數在類(lèi)上調用且必須使用 classmethod() 裝飾器:

@classmethod
def tearDownClass(cls):
    ...

查看 Class and Module Fixtures 獲取更詳細的說(shuō)明。

3.2 新版功能.

run(result=None)?

運行測試,將結果收集至作為 result 傳入的 TestResult。 如果 result 被省略或為 None,則會(huì )創(chuàng )建一個(gè)臨時(shí)的結果對象(通過(guò)調用 defaultTestResult() 方法)并使用它。 結果對象會(huì )被返回給 run() 的調用方。

同樣的效果也可通過(guò)簡(jiǎn)單地調用 TestCase 實(shí)例來(lái)達成。

在 3.3 版更改: 之前版本的 run 不會(huì )返回結果。 也不會(huì )對實(shí)例執行調用。

skipTest(reason)?

在測試方法或 setUp() 執行期間調用此方法將跳過(guò)當前測試。 詳情參見(jiàn) 跳過(guò)測試與預計的失敗。

3.1 新版功能.

subTest(msg=None, **params)?

返回一個(gè)上下文管理器以將其中的代碼塊作為子測試來(lái)執行。 可選的 msgparams 是將在子測試失敗時(shí)顯示的任意值,以便讓你能清楚地標識它們。

一個(gè)測試用例可以包含任意數量的子測試聲明,并且它們可以任意地嵌套。

查看 使用子測試區分測試迭代 獲取更詳細的信息。

3.4 新版功能.

debug()?

運行測試而不收集結果。 這允許測試所引發(fā)的異常被傳遞給調用方,并可被用于支持在調試器中運行測試。

TestCase 類(lèi)提供了一些斷言方法用于檢查并報告失敗。 下表列出了最常用的方法(請查看下文的其他表來(lái)了解更多的斷言方法):

方法

檢查對象

引入版本

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 參數,如果指定了該參數,它將被用作測試失敗時(shí)的錯誤消息 (另請參閱 longMessage)。 請注意將 msg 關(guān)鍵字參數傳給 assertRaises(), assertRaisesRegex(), assertWarns(), assertWarnsRegex() 的前提是它們必須被用作上下文管理器。

assertEqual(first, second, msg=None)?

測試 firstsecond 是否相等。 如果兩個(gè)值的比較結果是不相等,則測試將失敗。

此外,如果 firstsecond 的類(lèi)型完全相同且屬于 list, tuple, dict, set, frozenset 或 str 或者屬于通過(guò) addTypeEqualityFunc() 注冊子類(lèi)的類(lèi)型則將會(huì )調用類(lèi)型專(zhuān)屬的相等判斷函數以便生成更有用的默認錯誤消息 (另請參閱 類(lèi)型專(zhuān)屬方法列表)。

在 3.1 版更改: 增加了對類(lèi)型專(zhuān)屬的相等判斷函數的自動(dòng)調用。

在 3.2 版更改: 增加了 assertMultiLineEqual() 作為用于比較字符串的默認類(lèi)型相等判斷函數。

assertNotEqual(first, second, msg=None)?

測試 firstsecond 是否不等。 如果兩個(gè)值的比較結果是相等,則測試將失敗。

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

測試 expr 是否為真值(或假值)。

請注意這等價(jià)于 bool(expr) is True 而不等價(jià)于 expr is True (后者要使用 assertIs(expr, True))。 當存在更專(zhuān)門(mén)的方法時(shí)也應避免使用此方法 (例如應使用 assertEqual(a, b) 而不是 assertTrue(a == b)),因為它們在測試失敗時(shí)會(huì )提供更有用的錯誤消息。

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

測試 firstsecond 是 (或不是) 同一個(gè)對象。

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 (此參數可以為一個(gè)類(lèi)或包含類(lèi)的元組,即 isinstance() 所接受的參數) 的實(shí)例。 要檢測是否為指定類(lèi)型,請使用 assertIs(type(obj), cls)。

3.2 新版功能.

還可以使用下列方法來(lái)檢查異常、警告和日志消息的產(chǎn)生:

方法

檢查對象

引入版本

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

fun(*args, **kwds) 引發(fā)了 exc

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

fun(*args, **kwds) 引發(fā)了 exc 并且消息可與正則表達式 r 相匹配

3.1

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

fun(*args, **kwds) 引發(fā)了 warn

3.2

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

fun(*args, **kwds) 引發(fā)了 warn 并且消息可與正則表達式 r 相匹配

3.2

assertLogs(logger, level)

with 代碼塊在 logger 上使用了最小的 level 級別寫(xiě)入日志

3.4

assertNoLogs(logger, level)

with 代碼塊沒(méi)有在

logger 上使用最小的 level 級別寫(xiě)入日志

3.10

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

測試當 callable 附帶任何同時(shí)被傳給 assertRaises() 的位置或關(guān)鍵字參數被調用時(shí)是否引發(fā)了異常。 如果引發(fā)了 exception 則測試通過(guò),如果引發(fā)了另一個(gè)異常則報錯,或者如果未引發(fā)任何異常則測試失敗。 要捕獲一組異常中的任何一個(gè),可以將包含多個(gè)異常類(lèi)的元組作為 exception 傳入。

如果只給出了 exception 和可能的 msg 參數,則返回一個(gè)上下文管理器以便被測試的代碼可以被寫(xiě)成內聯(lián)形式而不是被寫(xiě)成函數:

with self.assertRaises(SomeException):
    do_something()

當被作為上下文管理器使用時(shí),assertRaises() 接受額外的關(guān)鍵字參數 msg。

上下文管理器將把捕獲的異常對象存入在其 exception 屬性中。 這適用于需要對所引發(fā)異常執行額外檢查的場(chǎng)合:

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 關(guān)鍵字參數在作為上下文管理器時(shí)使用。

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

assertRaises() 類(lèi)似但還會(huì )測試 regex 是否匹配被引發(fā)異常的字符串表示形式。 regex 可以是一個(gè)正則表達式對象或包含正則表達式的字符串以提供給 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 關(guān)鍵字參數在作為上下文管理器時(shí)使用。

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

測試當 callable 附帶任何同時(shí)被傳給 assertWarns() 的位置或關(guān)鍵字參數被調用時(shí)是否觸發(fā)了警告。 如果觸發(fā)了 warning 則測試通過(guò),否則測試失敗。 引發(fā)任何異常則報錯。 要捕獲一組警告中的任何一個(gè),可將包含多個(gè)警告類(lèi)的元組作為 warnings 傳入。

如果只給出了 warning 和可能的 msg 參數,則返回一個(gè)上下文管理器以便被測試的代碼可以被寫(xiě)成內聯(lián)形式而不是被寫(xiě)成函數:

with self.assertWarns(SomeWarning):
    do_something()

當被作為上下文管理器使用時(shí),assertWarns() 接受額外的關(guān)鍵字參數 msg。

上下文管理器將把捕獲的警告對象保存在其 warning 屬性中,并把觸發(fā)警告的源代碼行保存在 filenamelineno 屬性中。 這適用于需要對捕獲的警告執行額外檢查的場(chǎng)合:

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

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

無(wú)論被調用時(shí)警告過(guò)濾器是否就位此方法均可工作。

3.2 新版功能.

在 3.3 版更改: 增加了 msg 關(guān)鍵字參數在作為上下文管理器時(shí)使用。

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

assertWarns() 類(lèi)似但還會(huì )測試 regex 是否匹配被觸發(fā)警告的消息文本。 regex 可以是一個(gè)正則表達式對象或包含正則表達式的字符串以提供給 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 關(guān)鍵字參數在作為上下文管理器時(shí)使用。

assertLogs(logger=None, level=None)?

一個(gè)上下文管理器,它測試在 logger 或其子對象上是否至少記錄了一條至少為指定 level 以上級別的消息。

如果給出了 logger 則它應為一個(gè) logging.Logger 對象或為一個(gè)指定日志記錄器名稱(chēng)的 str。 默認為根日志記錄器,它將捕獲未被非傳播型后繼日志記錄器所攔阻的所有消息。

如果給出了 level 則它應為一個(gè)用數字表示的日志記錄級別或其字符串形式 (例如 "ERROR"logging.ERROR)。 默認為 logging.INFO。

如果在 with 代碼塊內部發(fā)出了至少一條與 loggerlevel 條件相匹配的消息則測試通過(guò),否則測試失敗。

上下文管理器返回的對象是一個(gè)記錄輔助器,它會(huì )記錄所匹配的日志消息。 它有兩個(gè)屬性:

records?

所匹配的日志消息 logging.LogRecord 對象組成的列表。

output?

str 對象組成的列表,內容為所匹配消息經(jīng)格式化后的輸出。

示例:

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)?

一個(gè)上下文管理器,它測試在 logger 或其子對象上是否未記錄任何至少為指定 level 以上級別的消息。

如果給出了 logger 則它應為一個(gè) logging.Logger 對象或為一個(gè)指定日志記錄器名稱(chēng)的 str。 默認為根日志記錄器,它將捕獲所有消息。

如果給出了 level 則它應為一個(gè)用數字表示的日志記錄級別或其字符串形式 (例如 "ERROR"logging.ERROR)。 默認為 logging.INFO。

assertLogs() 不同,上下文管理器將不返回任何對象。

3.10 新版功能.

還有其他一些方法可用于執行更專(zhuān)門(mén)的檢查,例如:

方法

檢查對象

引入版本

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 具有同樣數量的相同元素,無(wú)論其順序如何。

3.2

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

測試 firstsecond 是否幾乎相等,比較的標準是計算差值并舍入到 places 所指定的十進(jìn)制位數 (默認為 7 位),再與零相比較。 請注意此方法是將結果值舍入到指定的 十進(jìn)制位數 (即相當于 round() 函數) 而非 有效位數。

如果提供了 delta 而非 placesfirstsecond 之間的差值必須小于等于 (或大于) delta。

同時(shí)提供 deltaplaces 將引發(fā) TypeError。

在 3.2 版更改: assertAlmostEqual() 會(huì )自動(dòng)將幾乎相等的對象視為相等。 而如果對象相等則 assertNotAlmostEqual() 會(huì )自動(dòng)測試失敗。 增加了 delta 關(guān)鍵字參數。

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)?

測試一個(gè) regex 搜索匹配(或不匹配) 文本。如果不匹配,錯誤信息中將包含匹配模式和 文本*(或部分匹配失敗的 *文本)。regex 可以是正則表達式對象或能夠用于 re.search() 的包含正則表達式的字符串。

3.1 新版功能: 以方法名``assertRegexpMatches``添加。

在 3.2 版更改: 方法 assertRegexpMatches() 已被改名為 assertRegex()。

3.2 新版功能: assertNotRegex()

3.5 新版功能: assertNotRegexpMatches 這個(gè)名字是 assertNotRegex() 的已被棄用的別名。

assertCountEqual(first, second, msg=None)?

測試序列 firstsecond 是否包含同樣的元素,無(wú)論其順序如何。 當存在差異時(shí),將生成一條錯誤消息來(lái)列出兩個(gè)序列之間的差異。

重復的元素 不會(huì )firstsecond 的比較中被忽略。 它會(huì )檢查每個(gè)元素在兩個(gè)序列中的出現次數是否相同。 等價(jià)于: assertEqual(Counter(list(first)), Counter(list(second))) 但還適用于包含不可哈希對象的序列。

3.2 新版功能.

assertEqual() 方法會(huì )將相同類(lèi)型對象的相等性檢查分派給不同的類(lèi)型專(zhuān)屬方法。 這些方法已被大多數內置類(lèi)型所實(shí)現,但也可以使用 addTypeEqualityFunc() 來(lái)注冊新的方法:

addTypeEqualityFunc(typeobj, function)?

注冊一個(gè)由 assertEqual() 調用的特定類(lèi)型專(zhuān)屬方法來(lái)檢查恰好為相同 typeobj (而非子類(lèi)) 的兩個(gè)對象是否相等。 function 必須接受兩個(gè)位置參數和第三個(gè) msg=None 關(guān)鍵字參數,就像 assertEqual() 那樣。 當檢測到前兩個(gè)形參之間不相等時(shí)它必須引發(fā) self.failureException(msg) -- 可能還會(huì )提供有用的信息并在錯誤消息中詳細解釋不相等的原因。

3.1 新版功能.

以下是 assertEqual() 自動(dòng)選用的不同類(lèi)型的比較方法。一般情況下不需要直接在測試中調用這些方法。

方法

用作比較

引入版本

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 相等。 當不相等時(shí)將在錯誤消息中包括兩個(gè)字符串之間差異的高亮顯示。 此方法會(huì )在通過(guò) assertEqual() 進(jìn)行字符串比較時(shí)默認被使用。

3.1 新版功能.

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

測試兩個(gè)序列是否相等。 如果提供了 seq_type,則 firstsecond 都必須為 seq_type 的實(shí)例否則將引發(fā)失敗。 如果兩個(gè)序列不相等則會(huì )構造一個(gè)錯誤消息來(lái)顯示兩者之間的差異。

此方法不會(huì )被 assertEqual() 直接調用,但它會(huì )被用于實(shí)現 assertListEqual()assertTupleEqual()。

3.1 新版功能.

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

測試兩個(gè)列表或元組是否相等。 如果不相等,則會(huì )構造一個(gè)錯誤消息來(lái)顯示兩者之間的差異。 如果某個(gè)形參的類(lèi)型不正確也會(huì )引發(fā)錯誤。 這些方法會(huì )在通過(guò) assertEqual() 進(jìn)行列表或元組比較時(shí)默認被使用。

3.1 新版功能.

assertSetEqual(first, second, msg=None)?

測試兩個(gè)集合是否相等。 如果不相等,則會(huì )構造一個(gè)錯誤消息來(lái)列出兩者之間的差異。 此方法會(huì )在通過(guò) assertEqual() 進(jìn)行集合或凍結集合比較時(shí)默認被使用。

如果 firstsecond 沒(méi)有 set.difference() 方法則測試失敗。

3.1 新版功能.

assertDictEqual(first, second, msg=None)?

測試兩個(gè)字典是否相等。 如果不相等,則會(huì )構造一個(gè)錯誤消息來(lái)顯示兩個(gè)字典的差異。 此方法會(huì )在對 assertEqual() 的調用中默認被用來(lái)進(jìn)行字典的比較。

3.1 新版功能.

最后 TestCase 還提供了以下的方法和屬性:

fail(msg=None)?

無(wú)條件地發(fā)出測試失敗消息,附帶錯誤消息 msgNone。

failureException?

這個(gè)類(lèi)屬性給出測試方法所引發(fā)的異常。 如果某個(gè)測試框架需要使用專(zhuān)門(mén)的異常,并可能附帶額外的信息,則必須子類(lèi)化該類(lèi)以便與框架“正?;?dòng)”。 這個(gè)屬性的初始值為 AssertionError。

longMessage?

這個(gè)類(lèi)屬性決定當將一個(gè)自定義失敗消息作為 msg 參數傳給一個(gè)失敗的 assertXYY 調用時(shí)會(huì )發(fā)生什么。默認值為 True。 在此情況下,自定義消息會(huì )被添加到標準失敗消息的末尾。 當設為 False 時(shí),自定義消息會(huì )替換標準消息。

類(lèi)設置可以通過(guò)在調用斷言方法之前將一個(gè)實(shí)例屬性 self.longMessage 賦值為 TrueFalse 在單個(gè)測試方法中進(jìn)行重載。

類(lèi)設置會(huì )在每個(gè)測試調用之前被重置。

3.1 新版功能.

maxDiff?

這個(gè)屬性控制來(lái)自在測試失敗時(shí)報告 diffs 的斷言方法的 diffs 輸出的最大長(cháng)度。 它默認為 80*8 個(gè)字符。 這個(gè)屬性所影響的斷言方法有 assertSequenceEqual() (包括所有委托給它的序列比較方法), assertDictEqual() 以及 assertMultiLineEqual()。

maxDiff 設為 None 表示不限制 diffs 的最大長(cháng)度。

3.2 新版功能.

測試框架可使用下列方法來(lái)收集測試的有關(guān)信息:

countTestCases()?

返回此測試對象所提供的測試數量。 對于 TestCase 實(shí)例,該數量將總是為 1。

defaultTestResult()?

返回此測試類(lèi)所要使用的測試結果類(lèi)的實(shí)例(如果未向 run() 方法提供其他結果實(shí)例)。

對于 TestCase 實(shí)例,該返回值將總是為 TestResult 的實(shí)例;TestCase 的子類(lèi)應當在有必要時(shí)重載此方法。

id()?

返回一個(gè)標識指定測試用例的字符串。 該返回值通常為測試方法的完整名稱(chēng),包括模塊名和類(lèi)名。

shortDescription()?

返回測試的描述,如果未提供描述則返回 None。 此方法的默認實(shí)現將在可用的情況下返回測試方法的文檔字符串的第一行,或者返回 None。

在 3.1 版更改: 在 3.1 中已修改此方法將測試名稱(chēng)添加到簡(jiǎn)短描述中,即使存在文檔字符串。 這導致了與單元測試擴展的兼容性問(wèn)題因而在 Python 3.2 中將添加測試名稱(chēng)操作改到 TextTestResult 中。

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

tearDown() 之后添加了一個(gè)要調用的函數來(lái)清理測試期間所使用的資源。 函數將按它們被添加的相反順序被調用 (LIFO)。 它們在調用時(shí)將附帶它們被添加時(shí)傳給 addCleanup() 的任何參數和關(guān)鍵字參數。

如果 setUp() 失敗,即意味著(zhù) tearDown() 未被調用,則已添加的任何清理函數仍將被調用。

3.1 新版功能.

enterContext(cm)?

Enter the supplied context manager. If successful, also add its __exit__() method as a cleanup function by addCleanup() and return the result of the __enter__() method.

3.11 新版功能.

doCleanups()?

此方法會(huì )在 tearDown() 之后,或者如果 setUp() 引發(fā)了異常則會(huì )在 setUp() 之后被調用。

它將負責調用由 addCleanup() 添加的所有清理函數。 如果你需要在 tearDown() 之前 調用清理函數則可以自行調用 doCleanups()。

doCleanups() 每次會(huì )彈出清理函數棧中的一個(gè)方法,因此它可以在任何時(shí)候被調用。

3.1 新版功能.

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

在A(yíng)dd a function to be called after tearDownClass() 之后添加了一個(gè)要調用的函數來(lái)清理測試類(lèi)運行期間所使用的資源。 函數將按它們被添加的相反順序被調用 (LIFO)。 它們在調用時(shí)將附帶它們被添加時(shí)傳給 addClassCleanup() 的任何參數和關(guān)鍵字參數。

如果 setUpClass() 失敗,即意味著(zhù) tearDownClass() 未被調用,則已添加的任何清理函數仍將被調用。

3.8 新版功能.

classmethod enterClassContext(cm)?

Enter the supplied context manager. If successful, also add its __exit__() method as a cleanup function by addClassCleanup() and return the result of the __enter__() method.

3.11 新版功能.

classmethod doClassCleanups()?

此方法會(huì )在 tearDownClass() 之后無(wú)條件地被調用,或者如果 setUpClass() 引發(fā)了異常則會(huì )在 setUpClass() 之后被調用。

它將負責訪(fǎng)問(wèn)由 addClassCleanup() 添加的所有清理函數。 如果你需要在 tearDownClass() 之前 調用清理函數則可以自行調用 doClassCleanups()。

doClassCleanups() 每次會(huì )彈出清理函數棧中的一個(gè)方法,因此它在任何時(shí)候被調用。

3.8 新版功能.

class unittest.IsolatedAsyncioTestCase(methodName='runTest')?

這個(gè)類(lèi)提供了與 TestCase 類(lèi)似的 API 并也接受協(xié)程作為測試函數。

3.8 新版功能.

coroutine asyncSetUp()?

為測試預備而調用的方法。 此方法會(huì )在 setUp() 之后被調用。 此方法將在調用測試方法之前立即被調用;除了 AssertionErrorSkipTest,此方法所引發(fā)的任何異常都將被視為錯誤而非測試失敗。 默認的實(shí)現將不做任何事情。

coroutine asyncTearDown()?

在測試方法被調用并記錄結果之后立即被調用的方法。 此方法會(huì )在 tearDown() 之前被調用。 此方法即使在測試方法引發(fā)異常時(shí)仍會(huì )被調用,因此子類(lèi)中的實(shí)現將需要特別注意檢查內部狀態(tài)。 除 AssertionErrorSkipTest 外,此方法所引發(fā)的任何異常都將被視為額外的錯誤而非測試失?。ㄒ蚨鴷?huì )增加總計錯誤報告數)。 此方法將只在 asyncSetUp() 成功執行時(shí)被調用,無(wú)論測試方法的結果如何。 默認的實(shí)現將不做任何事情。

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

此方法接受一個(gè)可被用作清理函數的協(xié)程。

coroutine enterAsyncContext(cm)?

Enter the supplied asynchronous context manager. If successful, also add its __aexit__() method as a cleanup function by addAsyncCleanup() and return the result of the __aenter__() method.

3.11 新版功能.

run(result=None)?

設置一個(gè)新的事件循環(huán)來(lái)運行測試,將結果收集至作為 result 傳入的 TestResult。 如果 result 被省略或為 None,則會(huì )創(chuàng )建一個(gè)臨時(shí)的結果對象(通過(guò)調用 defaultTestResult() 方法)并使用它。 結果對象會(huì )被返回給 run() 的調用方。 在測試結束時(shí)事件循環(huán)中的所有任務(wù)都將被取消。

一個(gè)顯示先后順序的例子:

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 將會(huì )包含 ["setUp", "asyncSetUp", "test_response", "asyncTearDown", "tearDown", "cleanup"]。

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

這個(gè)類(lèi)實(shí)現了 TestCase 的部分接口,允許測試運行方驅動(dòng)測試,但不提供可被測試代碼用來(lái)檢查和報告錯誤的方法。 這個(gè)類(lèi)被用于創(chuàng )建使用傳統測試代碼的測試用例,允許它被集成到基于 unittest 的測試框架中。

已棄用的別名?

由于歷史原因,某些 TestCase 方法具有一個(gè)或幾個(gè)已目前已棄用的別名。 下表列出了它們的正確名稱(chēng)和已棄用的別名:

方法名

已棄用的別名

已棄用的別名

assertEqual()

failUnlessEqual

assertEquals

assertNotEqual()

failIfEqual

assertNotEquals

assertTrue()

failUnless

assert_

assertFalse()

failIf

assertRaises()

failUnlessRaises

assertAlmostEqual()

failUnlessAlmostEqual

assertAlmostEquals

assertNotAlmostEqual()

failIfAlmostEqual

assertNotAlmostEquals

assertRegex()

assertRegexpMatches

assertNotRegex()

assertNotRegexpMatches

assertRaisesRegex()

assertRaisesRegexp

3.1 版后已移除: 在第二列中列出的 fail* 別名已經(jīng)被棄用。

3.2 版后已移除: 在第三列中列出的 assert* 別名已經(jīng)被棄用。

3.2 版后已移除: assertRegexpMatchesassertRaisesRegexp 已經(jīng)被重命名為 assertRegex()assertRaisesRegex()。

3.5 版后已移除: assertNotRegexpMatches 這個(gè)名稱(chēng)已被棄用并應改用 assertNotRegex()。

分組測試?

class unittest.TestSuite(tests=())?

這個(gè)類(lèi)代表對單獨測試用例和測試套件的聚合。 這個(gè)類(lèi)提供給測試運行方所需的接口以允許其像任何其他測試用例一樣運行。 運行一個(gè) TestSuite 實(shí)例與對套件執行迭代來(lái)逐一運行每個(gè)測試的效果相同。

如果給出了 tests,則它必須是一個(gè)包含單獨測試用例的可迭代對象或是將被用于初始構建測試套件的其他測試套件。 還有一些附加的方法會(huì )被提供用來(lái)在隨后向測試集添加測試用例和測試套件。

TestSuite 對象的行為與 TestCase 對象很相似,區別在于它們并不會(huì )真正實(shí)現一個(gè)測試。 它們會(huì )被用來(lái)將測試聚合為多個(gè)要同時(shí)運行的測試分組。 還有一些附加的方法會(huì )被用來(lái)向 TestSuite 實(shí)例添加測試:

addTest(test)?

向測試套件添加 TestCaseTestSuite。

addTests(tests)?

將來(lái)自包含 TestCaseTestSuite 實(shí)例的可迭代對象的所有測試添加到這個(gè)測試套件。

這等價(jià)于對 tests 進(jìn)行迭代,并為其中的每個(gè)元素調用 addTest()。

TestSuiteTestCase 共享下列方法:

run(result)?

運行與這個(gè)套件相關(guān)聯(lián)的測試,將結果收集到作為 result 傳入的測試結果對象中。 請注意與 TestCase.run() 的區別,TestSuite.run() 必須傳入結果對象。

debug()?

運行與這個(gè)套件相關(guān)聯(lián)的測試而不收集結果。 這允許測試所引發(fā)的異常被傳遞給調用方并可被用于支持在調試器中運行測試。

countTestCases()?

返回此測試對象所提供的測試數量,包括單獨的測試和子套件。

__iter__()?

TestSuite 分組的測試總是可以通過(guò)迭代來(lái)訪(fǎng)問(wèn)。 其子類(lèi)可以通過(guò)重載 __iter__() 來(lái)惰性地提供測試。 請注意此方法可在單個(gè)套件上多次被調用(例如在計數測試或相等性比較時(shí)),為此在 TestSuite.run() 之前重復迭代所返回的測試對于每次調用迭代都必須相同。 在 TestSuite.run() 之后,調用方不應繼續訪(fǎng)問(wèn)此方法所返回的測試,除非調用方使用重載了 TestSuite._removeTestAtIndex() 的子類(lèi)來(lái)保留對測試的引用。

在 3.2 版更改: 在較早的版本中 TestSuite 會(huì )直接訪(fǎng)問(wèn)測試而不是通過(guò)迭代,因此只重載 __iter__() 并不足以提供所有測試。

在 3.4 版更改: 在較早的版本中 TestSuite 會(huì )在 TestSuite.run() 之后保留對每個(gè) TestCase 的引用。 其子類(lèi)可以通過(guò)重載 TestSuite._removeTestAtIndex() 來(lái)恢復此行為。

TestSuite 對象的典型應用中,run() 方法是由 TestRunner 發(fā)起調用而不是由最終用戶(hù)測試來(lái)控制。

加載和運行測試?

class unittest.TestLoader?

TestLoader 類(lèi)可被用來(lái)基于類(lèi)和模塊創(chuàng )建測試套件。 通常,沒(méi)有必要創(chuàng )建該類(lèi)的實(shí)例;unittest 模塊提供了一個(gè)可作為 unittest.defaultTestLoader 共享的實(shí)例。 但是,使用子類(lèi)或實(shí)例允許對某些配置屬性進(jìn)行定制。

TestLoader 對象具有下列屬性:

errors?

包含在加載測試期間遇到的非致命錯誤的列表。 在任何時(shí)候都不會(huì )被加載方重置。 致命錯誤是通過(guò)相關(guān)方法引發(fā)一個(gè)異常來(lái)向調用方發(fā)出信號的。 非致命錯誤也是由一個(gè)將在運行時(shí)引發(fā)原始錯誤的合成測試來(lái)提示的。

3.5 新版功能.

TestLoader 對象具有下列方法:

loadTestsFromTestCase(testCaseClass)?

返回一個(gè)包含在 TestCase 所派生的 testCaseClass 中的所有測試用例的測試套件。

會(huì )為每個(gè)由 getTestCaseNames() 指明的方法創(chuàng )建一個(gè)測試用例實(shí)例。 在默認情況下這些都是以 test 開(kāi)頭的方法名稱(chēng)。 如果 getTestCaseNames() 不返回任何方法,但 runTest() 方法已被實(shí)現,則會(huì )為該方法創(chuàng )建一個(gè)單獨的測試用例。

loadTestsFromModule(module, pattern=None)?

返回包含在給定模塊中的所有測試用例的測試套件。 此方法會(huì )在 module 中搜索從派生自 TestCase 的類(lèi)并為該類(lèi)定義的每個(gè)測試方法創(chuàng )建一個(gè)類(lèi)實(shí)例。

備注

雖然使用 TestCase 所派生的類(lèi)的層級結構可以方便地共享配置和輔助函數,但在不打算直接實(shí)例化的基類(lèi)上定義測試方法并不能很好地配合此方法使用。 不過(guò),當配置有差異并且定義在子類(lèi)當中時(shí)這樣做還是有用處的。

如果一個(gè)模塊提供了 load_tests 函數則它將被調用以加載測試。 這允許模塊自行定制測試加載過(guò)程。 這就稱(chēng)為 load_tests protocol。 pattern 參數會(huì )被作為傳給 load_tests 的第三個(gè)參數。

在 3.2 版更改: 添加了對 load_tests 的支持。

在 3.5 版更改: 未寫(xiě)入文檔的非官方 use_load_tests 默認參數已被棄用并忽略,但是它仍然被接受以便向下兼容。 此方法現在還接受一個(gè)僅限關(guān)鍵字參數 pattern,它會(huì )被作為傳給 load_tests 的第三個(gè)參數。

loadTestsFromName(name, module=None)?

返回由給出了字符串形式規格描述的所有測試用例組成的測試套件。

描述名稱(chēng) name 是一個(gè)“帶點(diǎn)號的名稱(chēng)”,它可以被解析為一個(gè)模塊、一個(gè)測試用例類(lèi)、一個(gè)測試用例類(lèi)內部的測試方法、一個(gè) TestSuite 實(shí)例,或者一個(gè)返回 TestCaseTestSuite 實(shí)例的可調用對象。 這些檢查將按在此列出的順序執行;也就是說(shuō),一個(gè)可能的測試用例類(lèi)上的方法將作為“一個(gè)測試用例內部的測試方法”而非作為“一個(gè)可調用對象”被選定。

舉例來(lái)說(shuō),如果你有一個(gè)模塊 SampleTests,其中包含一個(gè)派生自 TestCase 的類(lèi) SampleTestCase,其中包含三個(gè)測試方法 (test_one(), test_two()test_three())。 則描述名稱(chēng) 'SampleTests.SampleTestCase' 將使此方法返回一個(gè)測試套件,它將運行全部三個(gè)測試方法。 使用描述名稱(chēng) 'SampleTests.SampleTestCase.test_two' 將使它返回一個(gè)測試套件,它將僅運行 test_two() 測試方法。 描述名稱(chēng)可以指向尚未被導入的模塊和包;它們將作為附帶影響被導入。

本模塊可以選擇相對于給定的 module 來(lái)解析 name。

在 3.5 版更改: 如果在遍歷 name 時(shí)發(fā)生了 ImportErrorAttributeError 則在運行時(shí)引發(fā)該錯誤的合成測試將被返回。 這些錯誤被包括在由 self.errors 所積累的錯誤中。

loadTestsFromNames(names, module=None)?

類(lèi)似于 loadTestsFromName(),但是接受一個(gè)名稱(chēng)序列而不是單個(gè)名稱(chēng)。 返回值是一個(gè)測試套件,它支持為每個(gè)名稱(chēng)所定義的所有測試。

getTestCaseNames(testCaseClass)?

返回由 testCaseClass 中找到的方法名稱(chēng)組成的已排序的序列;這應當是 TestCase 的一個(gè)子類(lèi)。

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

通過(guò)從指定的開(kāi)始目錄向其子目錄遞歸來(lái)找出所有測試模塊,并返回一個(gè)包含該結果的 TestSuite 對象。 只有與 pattern 匹配的測試文件才會(huì )被加載。 (使用 shell 風(fēng)格的模式匹配。) 只有可導入的模塊名稱(chēng)(即有效的 Python 標識符)將會(huì )被加載。

所有測試模塊都必須可以從項目的最高層級上導入。 如果起始目錄不是最高層級目錄則必須單獨指明最高層級目錄。

如果導入某個(gè)模塊失敗,比如因為存在語(yǔ)法錯誤,則會(huì )將其記錄為單獨的錯誤并將繼續查找模塊。 如果導入失敗是因為引發(fā)了 SkipTest,則會(huì )將其記錄為跳過(guò)而不是錯誤。

如果找到了一個(gè)包(即包含名為 __init__.py 的文件的目錄),則將在包中查找 load_tests 函數。 如果存在此函數則將對其執行調用 package.load_tests(loader, tests, pattern)。 測試發(fā)現操作會(huì )確保在執行期間僅檢查測試一次,即使 load_tests 函數本身調用了 loader.discover 也是如此。.

如果 load_tests 存在則發(fā)現操作 不會(huì ) 對包執行遞歸處理,load_tests 將負責加載包中的所有測試。is responsible for loading all tests in the package.

模式特意地不被當作 loader 屬性來(lái)保存以使包能夠自己繼續執行發(fā)現操作。 top_level_dir 則會(huì )被保存以使 load_tests 不需要將此參數傳入到 loader.discover()。

start_dir 可以是一個(gè)帶點(diǎn)號的名稱(chēng)或是一個(gè)目錄。

3.2 新版功能.

在 3.4 版更改: 在導入時(shí)引發(fā) SkipTest 的模塊會(huì )被記錄為跳過(guò),而不是錯誤。

在 3.4 版更改: start_dir 可以是一個(gè) 命名空間包。

在 3.4 版更改: 路徑在被導入之前會(huì )先被排序以使得執行順序保持一致,即使下層文件系統的順序不是取決于文件名的。

在 3.5 版更改: 現在 load_tests 會(huì )檢查已找到的包,無(wú)論它們的路徑是否與 pattern 匹配,因為包名稱(chēng)是無(wú)法與默認的模式匹配的。

在 3.11 版更改: start_dir can not be a namespace packages. It has been broken since Python 3.7 and Python 3.11 officially remove it.

TestLoader 的下列屬性可通過(guò)子類(lèi)化或在實(shí)例上賦值來(lái)配置:

testMethodPrefix?

給出將被解讀為測試方法的方法名稱(chēng)的前綴的字符串。 默認值為 'test'。

這會(huì )影響 getTestCaseNames() 以及所有 loadTestsFrom*() 方法。

sortTestMethodsUsing?

將被用來(lái)在 getTestCaseNames() 以及所有 loadTestsFrom*() 方法中比較方法名稱(chēng)以便對它們進(jìn)行排序。

suiteClass?

根據一個(gè)測試列表來(lái)構造測試套件的可調用對象。 不需要結果對象上的任何方法。 默認值為 TestSuite 類(lèi)。

這會(huì )影響所有 loadTestsFrom*() 方法。

testNamePatterns?

由 Unix shell 風(fēng)格通配符的測試名稱(chēng)模式組成的列表,供測試方法進(jìn)行匹配以包括在測試套件中(參見(jiàn) -v 選項)。

如果該屬性不為 None (默認值),則將要包括在測試套件中的所有測試方法都必須匹配該列表中的某個(gè)模式。 請注意匹配總是使用 fnmatch.fnmatchcase() 來(lái)執行,因此不同于傳給 -v 選項的模式,簡(jiǎn)單的子字符串模式將必須使用 * 通配符來(lái)進(jìn)行轉換。

這會(huì )影響所有 loadTestsFrom*() 方法。

3.7 新版功能.

class unittest.TestResult?

這個(gè)類(lèi)被用于編譯有關(guān)哪些測試執行成功而哪些失敗的信息。

存放一組測試的結果的 TestResult 對象。 TestCaseTestSuite 類(lèi)將確保結果被正確地記錄;測試創(chuàng )建者無(wú)須擔心如何記錄測試的結果。

建立在 unittest 之上的測試框架可能會(huì )想要訪(fǎng)問(wèn)通過(guò)運行一組測試所產(chǎn)生的 TestResult 對象用來(lái)報告信息;TestRunner.run() 方法是出于這個(gè)目的而返回 TestResult 實(shí)例的。

TestResult 實(shí)例具有下列屬性,在檢查運行一組測試的結果的時(shí)候很有用處。

errors?

一個(gè)包含 TestCase 實(shí)例和保存了格式化回溯信息的字符串 2 元組的列表。 每個(gè)元組代表一個(gè)引發(fā)了非預期的異常的測試。

failures?

一個(gè)包含 TestCase 實(shí)例和保存了格式化回溯信息的字符串 2 元組的列表。 每個(gè)元組代表一個(gè)使用 TestCase.assert*() 方法顯式地發(fā)出失敗信號的測試。

skipped?

一個(gè)包含 2-tuples of TestCase 實(shí)例和保存了跳過(guò)測試原因的字符串 2 元組的列表。

3.1 新版功能.

expectedFailures?

一個(gè)包含 TestCase 實(shí)例和保存了格式化回溯信息的 2 元組的列表。 每個(gè)元組代表測試用例的一個(gè)已預期的失敗或錯誤。

unexpectedSuccesses?

一個(gè)包含被標記為已預期失敗,但卻測試成功的 TestCase 實(shí)例的列表。

shouldStop?

當測試的執行應當被 stop() 停止時(shí)則設為 True。

testsRun?

目前已運行的測試的總數量。

buffer?

如果設為真值,sys.stdoutsys.stderr 將在 startTest()stopTest() 被調用之間被緩沖。 被收集的輸出將僅在測試失敗或發(fā)生錯誤時(shí)才會(huì )被回顯到真正的 sys.stdoutsys.stderr。 任何輸出還會(huì )被附加到失敗/錯誤消息中。

3.2 新版功能.

failfast?

如果設為真值則 stop() 將在首次失敗或錯誤時(shí)被調用,停止測試運行。

3.2 新版功能.

tb_locals?

如果設為真值則局部變量將被顯示在回溯信息中。

3.5 新版功能.

wasSuccessful()?

如果當前所有測試都已通過(guò)則返回 True,否則返回 False。

在 3.4 版更改: 如果有任何來(lái)自測試的 unexpectedSuccessesexpectedFailure() 裝飾器所標記則返回 False。

stop()?

此方法可被調用以提示正在運行的測試集要將 shouldStop 屬性設為 True 來(lái)表示其應當被中止。 TestRunner 對象應當認同此旗標并返回而不再運行任何額外的測試。

例如,該特性會(huì )被 TextTestRunner 類(lèi)用來(lái)在當用戶(hù)從鍵盤(pán)發(fā)出一個(gè)中斷信號時(shí)停止測試框架。 提供了 TestRunner 實(shí)現的交互式工具也可通過(guò)類(lèi)似方式來(lái)使用該特性。

TestResult 類(lèi)的下列方法被用于維護內部數據結構,并可在子類(lèi)中被擴展以支持額外的報告需求。 這特別適用于構建支持在運行測試時(shí)提供交互式報告的工具。

startTest(test)?

當測試用例 test 即將運行時(shí)被調用。

stopTest(test)?

在測試用例 test 已經(jīng)執行后被調用,無(wú)論其結果如何。

startTestRun()?

在任何測試被執行之前被調用一次。

3.1 新版功能.

stopTestRun()?

在所有測試被執行之后被調用一次。

3.1 新版功能.

addError(test, err)?

當測試用例 test 引發(fā)了非預期的異常時(shí)將被調用。 err 是一個(gè)元組,其形式與 sys.exc_info() 的返回值相同: (type, value, traceback)。

默認實(shí)現會(huì )將一個(gè)元組 (test, formatted_err) 添加到實(shí)例的 errors 屬性,其中 formatted_err 是派生自 err 的已格式化回溯信息。

addFailure(test, err)?

當測試用例 test 發(fā)出了失敗信號時(shí)將被調用。 err 是一個(gè)元組,其形式與 sys.exc_info() 的返回值相同: (type, value, traceback)。

默認實(shí)現會(huì )將一個(gè)元組 (test, formatted_err) 添加到實(shí)例的 failures 屬性,其中 formatted_err 是派生自 err 的已格式化回溯信息。

addSuccess(test)?

當測試用例 test 成功時(shí)被調用。

默認實(shí)現將不做任何操作。

addSkip(test, reason)?

當測試用例 test 被跳過(guò)時(shí)將被調用。 reason 是給出的跳過(guò)測試的理由。

默認實(shí)現會(huì )將一個(gè)元組 (test, reason) 添加到實(shí)例的 skipped 屬性。

addExpectedFailure(test, err)?

當測試用例 test 失敗或發(fā)生錯誤,但是使用了 expectedFailure() 裝飾器來(lái)標記時(shí)將被調用。

默認實(shí)現會(huì )將一個(gè)元組 (test, formatted_err) 添加到實(shí)例的 expectedFailures 屬性,其中 formatted_err 是派生自 err 的已格式化回溯信息。

addUnexpectedSuccess(test)?

當測試用例 test 使用了was marked with the expectedFailure() 裝飾器來(lái)標記,但是卻執行成功時(shí)將被調用。

默認實(shí)現會(huì )將該測試添加到實(shí)例的 unexpectedSuccesses 屬性。

addSubTest(test, subtest, outcome)?

當一個(gè)子測試結束時(shí)將被調用。 test 是對應于該測試方法的測試用例。 subtest 是一個(gè)描述該子測試的 TestCase 實(shí)例。

如果 outcomeNone,則該子測試執行成功。 否則,它將失敗并引發(fā)一個(gè)異常,outcome 是一個(gè)元組,其形式與 sys.exc_info() 的返回值相同: (type, value, traceback)。

默認實(shí)現在測試結果為成功時(shí)將不做任何事,并會(huì )將子測試的失敗記錄為普通的失敗。

3.4 新版功能.

class unittest.TextTestResult(stream, descriptions, verbosity)?

TestResult 的一個(gè)具體實(shí)現,由 TextTestRunner 使用。

3.2 新版功能: 這個(gè)類(lèi)在之前被命名為 _TextTestResult。 這個(gè)舊名字仍然作為別名存在,但已被棄用。

unittest.defaultTestLoader?

用于分享的 TestLoader 類(lèi)實(shí)例。 如果不需要自制 TestLoader,則可以使用該實(shí)例而不必重復創(chuàng )建新的實(shí)例。

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

一個(gè)將結果輸出到流的基本測試運行器。 如果 stream 為默認的 None,則會(huì )使用 sys.stderr 作為輸出流。 這個(gè)類(lèi)具有一些配置形參,但實(shí)際上都非常簡(jiǎn)單。 運行測試套件的圖形化應用程序應當提供替代實(shí)現。 這樣的實(shí)現應當在添加新特性到 unittest 時(shí)接受 **kwargs 作為修改構造運行器的接口。

在默認情況下這個(gè)運行器會(huì )顯示 DeprecationWarning, PendingDeprecationWarning, ResourceWarningImportWarning,即使它們 被默認忽略。 由 deprecated unittest methods 所導致的棄用警告也會(huì )被作為特例,并且當警告過(guò)濾器為 'default''always' 時(shí),對于每個(gè)模塊它們將僅顯示一次,以避免過(guò)多的警告消息。 此種行為可使用 Python 的 -Wd-Wa 選項 (參見(jiàn) 警告控制) 并讓 warnings 保持為 None 來(lái)覆蓋。

在 3.2 版更改: 增加了 warnings 參數。

在 3.2 版更改: 默認流會(huì )在實(shí)例化而不是在導入時(shí)被設為 sys.stderr。

在 3.5 版更改: 增加了 tb_locals 形參。

_makeResult()?

此方法將返回由 run() 使用的 TestResult 實(shí)例。 它不應當被直接調用,但可在子類(lèi)中被重載以提供自定義的 TestResult。

_makeResult() 會(huì )實(shí)例化傳給 TextTestRunner 構造器的 resultclass 參數所指定的類(lèi)或可迭代對象。 如果沒(méi)有提供 resultclass 則默認為 TextTestResult。 結果類(lèi)會(huì )使用以下參數來(lái)實(shí)例化:

stream, descriptions, verbosity
run(test)?

此方法是 TextTestRunner 的主要公共接口。 此方法接受一個(gè) TestSuiteTestCase 實(shí)例。 通過(guò)調用 _makeResult() 創(chuàng )建 TestResult 來(lái)運行測試并將結果打印到標準輸出。

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 加載一組測試并運行它們的命令行程序;這主要是為了讓測試模塊能方便地執行。 此函數的最簡(jiǎn)單用法是在測試腳本末尾包括下列行:

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

你可以通過(guò)傳入冗余參數運行測試以獲得更詳細的信息:

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

defaultTest 參數是要運行的單個(gè)測試名稱(chēng),或者如果未通過(guò) argv 指定任何測試名稱(chēng)則是包含多個(gè)測試名稱(chēng)的可迭代對象。 如果未指定或為 None 且未通過(guò) argv 指定任何測試名稱(chēng),則會(huì )運行在 module 中找到的所有測試。

argv 參數可以是傳給程序的選項列表,其中第一個(gè)元素是程序名。 如未指定或為 None,則會(huì )使用 sys.argv 的值。

testRunner 參數可以是測試運行器類(lèi)或是其已創(chuàng )建的實(shí)例。 在默認情況下 main 會(huì )調用 sys.exit() 并附帶一個(gè)退出碼來(lái)指明測試運行是成功還是失敗。

testLoader 參數必須是一個(gè) TestLoader 實(shí)例,其默認值為 defaultTestLoader。

main 支持通過(guò)傳入 exit=False 參數以便在交互式解釋器中使用。 這將在標準輸出中顯示結果而不調用 sys.exit():

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

failfast, catchbreakbuffer 形參的效果與同名的 command-line options 一致。

warnings 參數指定在運行測試時(shí)所應使用的 警告過(guò)濾器。 如果未指定,則默認的 None 會(huì )在將 -W 選項傳給 python 命令時(shí)被保留 (參見(jiàn) 警告控制),而在其他情況下將被設為 'default'。

調用 main 實(shí)際上將返回一個(gè) TestProgram 類(lèi)的實(shí)例。 這會(huì )把測試運行結果保存為 result 屬性。

在 3.1 版更改: 增加了 exit 形參。

在 3.2 版更改: 增加了 verbosity, failfast, catchbreak, bufferwarnings 形參。

在 3.4 版更改: defaultTest 形參被修改為也接受一個(gè)由測試名稱(chēng)組成的迭代器。

load_tests 協(xié)議?

3.2 新版功能.

模塊或包可以通過(guò)實(shí)現一個(gè)名為 load_tests 的函數來(lái)定制在正常測試運行或測試發(fā)現期間要如何從中加載測試。

如果一個(gè)測試模塊定義了 load_tests 則它將被 TestLoader.loadTestsFromModule() 調用并傳入下列參數:

load_tests(loader, standard_tests, pattern)

其中 pattern 會(huì )通過(guò) loadTestsFromModule 傳入。 它的默認值為 None。

它應當返回一個(gè) TestSuite。

loader 是執行載入操作的 TestLoader 實(shí)例。 standard_tests 是默認要從該模塊載入的測試。 測試模塊通常只需從標準測試集中添加或移除測試。 第三個(gè)參數是在作為測試發(fā)現的一部分載入包時(shí)使用的。

一個(gè)從指定 TestCase 類(lèi)集合中載入測試的 load_tests 函數看起來(lái)可能是這樣的:

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

如果發(fā)現操作是在一個(gè)包含包的目錄中開(kāi)始的,不論是通過(guò)命令行還是通過(guò)調用 TestLoader.discover(),則將在包 __init__.py 中檢查 load_tests。 如果不存在此函數,則發(fā)現將在包內部執行遞歸,就像它是另一個(gè)目錄一樣。 在其他情況下,包中測試的發(fā)現操作將留給 load_tests 執行,它將附帶下列參數被調用:

load_tests(loader, standard_tests, pattern)

這應當返回代表包中所有測試的 TestSuite。 (standard_tests 將只包含從 __init__.py 獲取的測試。)

因為模式已被傳入 load_tests 所以包可以自由地繼續(還可能修改)測試發(fā)現操作。 針對一個(gè)測試包的 '無(wú)操作' load_tests 函數看起來(lái)是這樣的:

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 版更改: 發(fā)現操作不會(huì )再檢查包名稱(chēng)是否匹配 pattern,因為包名稱(chēng)不可能匹配默認的模式。

類(lèi)與模塊設定?

類(lèi)與模塊設定是在 TestSuite 中實(shí)現的。 當測試套件遇到來(lái)自新類(lèi)的測試時(shí)則來(lái)自之前的類(lèi)(如果存在)的 tearDownClass() 會(huì )被調用,然后再調用來(lái)自新類(lèi)的 setUpClass()。

類(lèi)似地如果測試是來(lái)自之前的測試的另一個(gè)模塊則來(lái)自之前模塊的 tearDownModule 將被運行,然后再運行來(lái)自新模塊的 setUpModule。

在所有測試運行完畢后最終的 tearDownClasstearDownModule 將被運行。

請注意共享設定不適用于一些 [潛在的] 特性例如測試并行化并且它們會(huì )破壞測試隔離。 它們應當被謹慎地使用。

由 unittest 測試加載器創(chuàng )建的測試的默認順序是將所有來(lái)自相同模塊和類(lèi)的測試歸入相同分組。 這將導致 setUpClass / setUpModule (等) 對于每個(gè)類(lèi)和模塊都恰好被調用一次。 如果你將順序隨機化,以便使得來(lái)自不同模塊和類(lèi)的測試彼此相鄰,那么這些共享的設定函數就可能會(huì )在一次測試運行中被多次調用。

共享的設定不適用與非標準順序的套件。 對于不想支持共享設定的框架來(lái)說(shuō) BaseTestSuite 仍然可用。

如果在共享的設定函數中引發(fā)了任何異常則測試將被報告錯誤。 因為沒(méi)有對應的測試實(shí)例,所以會(huì )創(chuàng )建一個(gè) _ErrorHolder 對象(它具有與 TestCase 相同的接口)來(lái)代表該錯誤。 如果你只是使用標準 unittest 測試運行器那么這個(gè)細節并不重要,但是如果你是一個(gè)框架開(kāi)發(fā)者那么這可能會(huì )有關(guān)系。

setUpClass 和 tearDownClass?

這些必須被實(shí)現為類(lèi)方法:

import unittest

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

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

如果你希望在基類(lèi)上的 setUpClasstearDownClass 被調用則你必須自己云調用它們。 在 TestCase 中的實(shí)現是空的。

如果在 setUpClass 中引發(fā)了異常則類(lèi)中的測試將不會(huì )被運行并且 tearDownClass 也不會(huì )被運行。 跳過(guò)的類(lèi)中的 setUpClasstearDownClass 將不會(huì )被運行。 如果引發(fā)的異常是 SkipTest 異常則類(lèi)將被報告為已跳過(guò)而非發(fā)生錯誤。

setUpModule 和 tearDownModule?

這些應當被實(shí)現為函數:

def setUpModule():
    createConnection()

def tearDownModule():
    closeConnection()

如果在 setUpModule 中引發(fā)了異常則模塊中的任何測試都將不會(huì )被運行并且 tearDownModule 也不會(huì )被運行。 如果引發(fā)的異常是 SkipTest 異常則模塊將被報告為已跳過(guò)而非發(fā)生錯誤。

要添加即使在發(fā)生異常時(shí)也必須運行的清理代碼,請使用 addModuleCleanup:

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

tearDownModule() 之后添加一個(gè)要調用的函數來(lái)清理測試類(lèi)運行期間所使用的資源。 函數將按它們被添加的相反順序被調用 (LIFO)。 它們在調用時(shí)將附帶它們被添加時(shí)傳給 addModuleCleanup() 的任何參數和關(guān)鍵字參數。

如果 setUpModule() 失敗,即意味著(zhù) tearDownModule() 未被調用,則已添加的任何清理函數仍將被調用。

3.8 新版功能.

classmethod unittest.enterModuleContext(cm)?

Enter the supplied context manager. If successful, also add its __exit__() method as a cleanup function by addModuleCleanup() and return the result of the __enter__() method.

3.11 新版功能.

unittest.doModuleCleanups()?

此函數會(huì )在 tearDownModule() 之后無(wú)條件地被調用,或者如果 setUpModule() 引發(fā)了異常則會(huì )在 setUpModule() 之后被調用。

It is responsible for calling all the cleanup functions added by addModuleCleanup(). If you need cleanup functions to be called prior to tearDownModule() then you can call doModuleCleanups() yourself.

doModuleCleanups() 每次會(huì )彈出清理函數棧中的一個(gè)方法,因此它可以在任何時(shí)候被調用。

3.8 新版功能.

信號處理?

3.2 新版功能.

unittest 的 -c/--catch 命令行選項,加上 unittest.main()catchbreak 形參,提供了在測試運行期間處理 control-C 的更友好方式。 在捕獲中斷行為被啟用時(shí) control-C 將允許當前運行的測試能夠完成,而測試運行將隨后結束并報告已有的全部結果。 第二個(gè) control-C 將會(huì )正常地引發(fā) KeyboardInterrupt。

處理 control-C 信號的句柄會(huì )嘗試與安裝了自定義 signal.SIGINT 處理句柄的測試代碼保持兼容。 如果是 unittest 處理句柄而 不是 已安裝的 signal.SIGINT 處理句柄被調用,即它被系統在測試的下層替換并委托處理,則它會(huì )調用默認的處理句柄。 這通常會(huì )是替換了已安裝處理句柄并委托處理的代碼所預期的行為。 對于需要禁用 unittest control-C 處理的單個(gè)測試則可以使用 removeHandler() 裝飾器。

還有一些工具函數讓框架開(kāi)發(fā)者可以在測試框架內部啟用 control-C 處理功能。

unittest.installHandler()?

安裝 control-C 處理句柄。 當接收到 signal.SIGINT 時(shí)(通常是響應用戶(hù)按下 control-C)所有已注冊的結果都會(huì )執行 stop() 調用。

unittest.registerResult(result)?

注冊一個(gè) TestResult 對象用于 control-C 的處理。 注冊一個(gè)結果將保存指向它的弱引用,因此這并不能防止結果被作為垃圾回收。

如果 control-C 未被啟用則注冊 TestResult 對象將沒(méi)有任何附帶影響,因此不論是否啟用了該項處理測試框架都可以無(wú)條件地注冊他們獨立創(chuàng )建的所有結果。

unittest.removeResult(result)?

移除一個(gè)已注冊的結果。 一旦結果被移除則 stop() 將不再會(huì )作為針對 control-C 的響應在結果對象上被調用。

unittest.removeHandler(function=None)?

當不附帶任何參數被調用時(shí)此函數將移除已被安裝的 control-C 處理句柄。 此函數還可被用作測試裝飾器以在測試被執行時(shí)臨時(shí)性地移除處理句柄:

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