python / 3.7.2rc1 / all / library-unittest.html

unittest —单元测试框架

源代码: Lib/unittest/init.py


(如果您已经熟悉测试的基本概念,则可能要跳到assert 方法列表。)

unittest单元测试框架最初受 JUnit 启发,并且具有与其他语言中的主要单元测试框架类似的风格。它支持测试自动化,共享测试的设置和关闭代码,将测试聚合到集合中以及测试与报告框架的独立性。

为此,unittest以面向对象的方式支持一些重要的概念:

  • test fixture

    • 测试装置表示执行一个或多个测试所需的准备工作以及任何相关的清除操作。例如,这可能涉及创建临时或代理数据库,目录或启动服务器进程。
  • test case

    • 测试用例是单个测试单元。它检查对一组特定 Importing 的特定响应。 unittest提供了一个 Base ClassTestCase,可用于创建新的测试用例。
  • test suite

    • 测试套件是测试用例,测试套件或两者的集合。它用于汇总应一起执行的测试。
  • test runner

    • 测试运行程序是协调测试执行并向用户提供结果的组件。Running 者可以使用图形界面,文本界面,或返回特殊值以指示执行测试的结果。

See also

Python 源代码分发中的脚本Tools/unittestgui/unittestgui.py是用于测试发现和执行的 GUI 工具。这主要是为了使单元测试新手易于使用。对于生产环境,建议使用诸如BuildbotJenkinsHudson之类的连续集成系统来驱动测试。

Basic example

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

pass子类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) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... ok

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

OK

上面的示例显示了最常用的unittestFunction,这些Function足以满足许多日常测试需求。本文档的其余部分从第一个原理探讨了完整的Function集。

Command-Line Interface

可以从命令行使用 unittest 模块从模块,类甚至单个测试方法运行测试:

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

您可以传入一个列表,其中包含模块名称以及完全限定的类或方法名称的任意组合。

测试模块也可以pass文件路径指定:

python -m unittest tests/test_something.py

这使您可以使用 Shell 文件名完成来指定测试模块。指定的文件必须仍然可以作为模块导入。pass删除“ .py”并将路径分隔符转换为“。”,可将该路径转换为模块名称。如果要执行不可作为模块导入的测试文件,则应直接执行该文件。

您可以pass传递-v 标志来运行更详细(更详细)的测试:

python -m unittest -v test_module

在不带参数Test Discovery的情况下执行时:

python -m unittest

有关所有命令行选项的列表:

python -m unittest -h

在 3.2 版中进行了更改:在早期版本中,只能运行单独的测试方法,而不能运行模块或类。

Command-line options

unittest 支持以下命令行选项:

  • -b `,` `--buffer`

    • 在测试运行期间,将缓冲标准输出和标准错误流。pass测试期间的输出将被丢弃。在测试失败或错误时,通常会回显输出,并将其添加到失败消息中。
  • -c `,` `--catch`

    • 在测试运行期间,Control-Cawait 当前测试结束,然后报告到目前为止的所有结果。第二个 Control-C 引发正常的KeyboardInterrupt异常。

有关提供此Function的Function,请参见Signal Handling

  • -f `,` `--failfast`

    • 在第一个错误或失败时停止测试运行。
  • -k ``

    • 仅运行与模式或子字符串匹配的测试方法和类。此选项可以多次使用,在这种情况下,将包括与给定模式匹配的所有测试用例。

包含通配符(*)的模式使用fnmatch.fnmatchcase()与测试名称匹配;否则,使用简单的区分大小写的子字符串匹配。

模式与测试加载程序导入的标准测试方法名称匹配。

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

  • --locals ``
    • 在回溯中显示局部变量。

版本 3.2 中的新增Function:添加了命令行选项-b-c-f

3.5 版的新Function:命令行选项--locals

3.7 版的新Function:命令行选项-k

命令行还可以用于测试发现,运行项目中的所有测试或仅运行子集。

Test Discovery

3.2 版中的新Function。

Unittest 支持简单的测试发现。为了与测试发现兼容,所有测试文件都必须是modulespackages(包括namespace packages)可从项目的顶级目录导入(这意味着它们的文件名必须是有效的identifiers)。

测试发现在TestLoader.discover()中实现,但也可以从命令行使用。基本的命令行用法是:

cd project_directory
python -m unittest discover

Note

作为快捷方式,python -m unittest等效于python -m unittest discover。如果要传递参数以测试发现,则必须显式使用discover子命令。

discover子命令具有以下选项:

  • -v `,` `--verbose`

    • Verbose output
  • -s `` , --start-directory directory

    • 开始发现的目录(默认为.)
  • -p `` , --pattern pattern

    • 模式以匹配测试文件(默认为test*.py)
  • -t `` , --top-level-directory directory

    • 项目的顶层目录(默认为起始目录)

-s-p-t选项可以按位置 Sequences 作为位置参数传递。以下两个命令行是等效的:

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

除了作为路径外,还可以将包名称(例如myproject.subpackage.test)作为起始目录。然后,将提供您提供的软件包名称,并将其在文件系统上的位置用作起始目录。

Caution

测试发现pass导入来加载测试。一旦测试发现从开始目录中找到所有测试文件,您就可以指定将路径转换为要导入的程序包名称。例如foo/bar/baz.py将被导入为foo.bar.baz

如果您已全局安装了一个软件包,并try在该软件包的另一个副本上进行测试发现,则导入可能从错误的位置进行。如果发生这种情况,测试发现将警告您并退出。

如果您以包名而不是目录路径的形式提供开始目录,那么 Discover 会假设它从哪个导入位置进入您想要的位置,因此不会收到警告。

测试模块和软件包可以passload_tests protocol自定义测试加载和发现。

在版本 3.4 中进行了更改:测试发现支持namespace packages

组织测试代码

单元测试的基本构建块是测试用例-必须设置单个场景并检查其正确性。在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))

请注意,为了测试某些内容,我们使用TestCaseBase Class 提供的assert*()方法之一。如果测试失败,则会引发异常并显示一条解释性消息,并且unittest将测试用例标识为* failure 。其他任何异常都将被视为 errors *。

测试可能很多,并且它们的设置可能是重复的。幸运的是,我们可以pass实现名为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')

Note

pass根据字符串的内置 Sequences 对测试方法名称进行排序,可以确定各种测试的运行 Sequences。

如果在测试运行时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 实现将测试根据其测试的Function分组在一起。 unittest为此提供了一种机制:* test suite *,由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的此子类可用于包装现有的测试Function。还可以提供设置和拆卸Function。

给定以下测试Function:

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

可以使用可选的设置和拆卸方法如下创建等效的测试用例实例:

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

Note

即使可以使用FunctionTestCase将现有的测试库快速转换为基于unittest的系统,也不建议使用此方法。花时间设置适当的TestCase子类将使将来的测试重构变得更加轻松。

在某些情况下,现有测试可能是使用doctest模块编写的。如果是这样,doctest提供了一个DocTestSuite类,该类可以根据现有基于doctest的测试自动构建unittest.TestSuite实例。

跳过测试和预期的失败

3.1 版中的新Function。

Unittest 支持跳过单个测试方法甚至整个测试类别。此外,它支持将测试标记为“预期失败”,即已损坏且将失败的测试,但不应将其视为TestResult上的失败。

跳过测试仅是使用skip() decorator或其条件变量之一,在setUp()或测试方法中调用TestCase.skipTest()或直接提高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) ... skipped 'not supported in this library version'
test_nothing (__main__.MyTestCase) ... skipped 'demonstrating skipping'
test_maybe_skipped (__main__.MyTestCase) ... skipped 'external resource not available'
test_windows_support (__main__.MyTestCase) ... 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")

pass制作一个在测试中希望跳过测试的调用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(原因)

    • 无条件跳过装饰测试。 原因应说明为何跳过测试。
  • @ unittest. skipIf(条件原因)

    • 如果* condition *为 true,则跳过修饰的测试。
  • @ unittest. skipUnless(条件原因)

    • 除非* condition *为 true,否则跳过装饰性测试。
  • @ unittest. expectedFailure

    • 将测试标记为预期的失败。如果测试失败,则视为成功。如果测试pass,将被视为失败。
  • exception unittest. SkipTest(原因)

    • 引发此异常以跳过测试。

通常,您可以使用TestCase.skipTest()或跳过的装饰器之一,而不是直接提高它。

跳过的测试不会在它们周围运行setUp()tearDown()。跳过的类不会运行setUpClass()tearDownClass()。跳过的模块将不会运行setUpModule()tearDownModule()

使用子测试区分测试迭代

3.4 版的新Function。

如果您的测试之间的差异非常小(例如某些参数),则 unittest 允许您使用subTest()上下文 Management 器在测试方法的内部区分它们。

例如,以下测试:

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) (i=1)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 32, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

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

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

如果不使用子测试,则在第一次失败后执行将停止,并且错误将不那么容易诊断,因为不会显示i的值:

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

类和函数

本节深入介绍unittest的 API。

Test cases

    • class * unittest. TestCase(* methodName ='runTest'*)
    • TestCase类的实例表示unittest Universe 中的逻辑测试单元。该类旨在用作 Base Class,具体测试由具体的子类实现。此类实现测试运行程序所需的接口,以使其能够驱动测试,以及测试代码可用于检查和报告各种失败的方法。

TestCase的每个实例将运行一个基本方法:名为* methodName 的方法。在TestCase的大多数用法中,既不会更改 methodName *,也不会重新实现默认的runTest()方法。

在版本 3.2 中更改:TestCase可以成功实例化而无需提供* methodName *。这样可以更轻松地try使用交互式解释器中的TestCase

TestCase实例提供三组方法:一组用于运行测试,另一组由测试实现用于检查条件和报告故障,还有一些查询方法允许收集有关测试本身的信息。

第一组(运行测试)的方法是:

  • setUp ( )

    • 调用准备测试夹具的方法。在调用测试方法之前立即调用该方法。除了AssertionErrorSkipTest之外,此方法引发的任何异常都将被视为错误而不是测试失败。默认实现不执行任何操作。
  • tearDown ( )

    • 调用测试方法并记录结果后立即调用的方法。即使测试方法引发异常,也会调用此方法,因此子类中的实现在检查内部状态时可能需要格外小心。除AssertionErrorSkipTest之外,此方法引发的任何异常都将被视为附加错误,而不是测试失败(因此会增加报告的错误总数)。无论setUp()成功如何,都将调用此方法,而不管测试方法的结果如何。默认实现不执行任何操作。
  • setUpClass ( )

    • 在运行单个类中的测试之前调用的类方法。调用setUpClass时以类作为唯一参数,并且必须将其修饰为classmethod()
@classmethod
def setUpClass(cls):
    ...

有关更多详细信息,请参见类和模块夹具

3.2 版中的新Function。

  • tearDownClass ( )
    • 在单个类中的测试运行后调用的类方法。调用tearDownClass时以类作为唯一参数,并且必须将其修饰为classmethod()
@classmethod
def tearDownClass(cls):
    ...

有关更多详细信息,请参见类和模块夹具

3.2 版中的新Function。

  • run(* result = None *)
    • 运行测试,将结果收集到以* result 传递的TestResult对象中。如果Ellipsis result *或None,则会创建临时结果对象(pass调用defaultTestResult()方法)并使用。结果对象返回给run()的调用方。

只需调用TestCase实例,就可以达到相同的效果。

在版本 3.3 中进行了更改:run的早期版本未返回结果。都没有调用实例。

3.1 版中的新Function。

  • subTest(* msg = None ** params *)
    • 返回一个上下文 Management 器,该上下文 Management 器将附带的代码块作为子测试执行。 * msg params *是可选的,任意值,它们在子测试失败时显示,使您可以清楚地识别它们。

一个测试用例可以包含任意数量的子测试语句,并且它们可以任意嵌套。

有关更多信息,请参见使用子测试区分测试迭代

3.4 版的新Function。

  • debug ( )
    • 运行测试而不收集结果。这样可以将测试引发的异常传播到调用方,并可以用来支持在调试器下运行测试。

TestCase类提供了几种 assert 方法来检查和报告故障。下表列出了最常用的方法(有关更多 assert 方法,请参见下表):

Method Checks that New in
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

所有 assert 方法都接受一个* msg 参数,如果指定该参数,该参数将用作失败时的错误消息(另请参见longMessage)。请注意,仅当 msg *关键字参数用作上下文 Management 器时,它们才能传递给assertRaises()assertRaisesRegex()assertWarns()assertWarnsRegex()

  • assertEqual(* first second msg = None *)
    • 测试* first second *是否相等。如果值比较不相等,则测试将失败。

另外,如果* first second *是完全相同的类型,并且是 list,tuple,dict,set,frozenset 或 str 或子类向addTypeEqualityFunc()注册的任何类型之一,则将按 Sequences 调用特定于类型的相等函数生成更有用的默认错误消息(另请参见类型专用方法列表)。

在版本 3.1 中进行了更改:添加了类型特定的相等函数的自动调用。

在版本 3.2 中进行了更改:添加了assertMultiLineEqual()作为用于比较字符串的默认类型相等函数。

  • assertNotEqual(* first second msg = None *)

    • 测试* first second *不相等。如果这些值确实比较相等,则测试将失败。
  • assertTrue(* expr msg = None *)

    • assertFalse(* expr msg = None *)
      • 测试* expr *是否为 true(或 false)。

请注意,这等效于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 *)
      • 测试* first second *对同Pair象求值(或不求值)。

3.1 版中的新Function。

  • assertIsNone(* expr msg = None *)
    • assertIsNotNone(* expr msg = None *)
      • 测试* expr *是(或不是)None

3.1 版中的新Function。

  • assertIn((* member container msg = None *)
    • assertNotIn((* member container msg = None *)
      • 测试* member 是否在 container *中。

3.1 版中的新Function。

  • assertIsInstance(* obj cls msg = None *)
    • assertNotIsInstance(* obj cls msg = None *)

3.2 版中的新Function。

也可以使用以下方法检查异常,警告和日志消息的产生:

Method Checks that New in
assertRaises(exc,fun,* args,** kwds) fun(*args, **kwds)加注* exc *
assertRaisesRegex(exc,r,fun,* args,** kwds) fun(*args, **kwds)引发* exc ,并且消息与正则表达式 r *匹配 3.1
assertWarns(警告,有趣,* args,** kwds) fun(*args, **kwds)加注警告 3.2
assertWarnsRegex(warn,r,fun,* args,** kwds) fun(*args, **kwds)引发警告并且消息匹配正则表达式* r * 3.2
assertLogs(logger, level) with块以最低级别登录* logger * 3.4
  • assertRaises((* exception callable *, *args * kwds *)
    • assertRaises(* exception **,* msg = None *)

      • 测试是否使用也传递给assertRaises()的任何位置或关键字参数调用* callable 时引发了异常。如果引发 exception ,则测试pass;如果引发另一个异常,则测试pass;如果未引发异常,则测试pass。为了捕获一组异常中的任何一个,包含异常类的 Tuples 可以作为 exception *传递。

如果仅给出* exception 以及可能的 msg *参数,则返回一个上下文 Management 器,以便可以将内嵌代码而不是作为函数编写被测代码:

with self.assertRaises(SomeException):
    do_something()

用作上下文 Management 器时,assertRaises()接受附加的关键字参数* msg *。

上下文 Management 器会将捕获的异常对象存储在其exception属性中。如果要对引发的异常执行其他检查,这将很有用:

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

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

在版本 3.1 中进行了更改:添加了使用assertRaises()作为上下文 Management 器的Function。

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

在版本 3.3 中进行了更改:在用作上下文 Management 器时,添加了* 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')

or:

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

3.1 版的新Function:以名称assertRaisesRegexp添加。

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

在版本 3.3 中进行了更改:在用作上下文 Management 器时,添加了* msg *关键字参数。

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

      • 测试当使用任何也传递给assertWarns()的位置或关键字参数调用* callable 时,是否触发警告。如果警告被触发,则测试pass,否则就失败。任何异常都是错误。为了捕获任何一组警告,包含警告类的 Tuples 可以作为 warnings *传递。

如果仅给出* warning msg *参数,则返回一个上下文 Management 器,以便可以将内嵌代码而不是作为函数编写被测代码:

with self.assertWarns(SomeWarning):
    do_something()

用作上下文 Management 器时,assertWarns()接受附加的关键字参数* msg *。

上下文 Management 器会将捕获到的警告对象存储在其warning属性中,并将触发警告的源代码行存储在filenamelineno属性中。如果要对捕获到的警告进行其他检查,这将很有用:

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

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

无论调用时是否设置了警告过滤器,此方法均有效。

3.2 版中的新Function。

在版本 3.3 中进行了更改:在用作上下文 Management 器时,添加了* 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')

or:

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

3.2 版中的新Function。

在版本 3.3 中进行了更改:在用作上下文 Management 器时,添加了* msg *关键字参数。

  • assertLogs(* logger = None level = None *)
    • 上下文 Management 器,用于测试是否至少有给定的* level 记录在 logger *或其子级中的至少一条消息上。

如果指定了* logger *,则它应该是logging.Logger对象或str,并提供 Logger 的名称。默认值为 root logger,它将捕获所有消息。

如果给定,则* level *应该是数字日志记录级别或其等效字符串(例如"ERROR"logging.ERROR)。默认值为logging.INFO

如果with块内发出的至少一条消息符合* logger level *条件,则测试pass。否则,测试将失败。

上下文 Management 器返回的对象是一个记录助手,它跟踪匹配的日志消息。它具有两个属性:

  • records

    -匹配日志消息的logging.LogRecord个对象的列表。

  • output

    -str个对象的列表,带有匹配消息的格式化输出。

Example:

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 版的新Function。

还有其他用于执行更具体检查的方法,例如:

Method Checks that New in
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) * a b *具有相同编号的相同元素,而不管其 Sequences 如何。 3.2
  • assertAlmostEqual((* first second places = 7 msg = None delta = None *)
    • assertNotAlmostEqual((* first second places = 7 msg = None delta = None *)
      • pass计算差值,四舍五入到给定的小数位数* places (默认为 7),然后比较零,来测试 first second 近似(或不近似)相等。请注意,这些方法将值四舍五入为小数位数的给定数量(即类似于round()函数),而不是有效位数*。

如果提供了* delta 而不是 places ,那么 first second 之间的差值必须小于或等于(或大于) delta *。

同时提供* delta places *会引发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 版中的新Function。

  • assertRegex(* text regex msg = None *)
    • assertNotRegex(* text regex msg = None *)
      • 测试* regex 搜索是否匹配(或不匹配) text 。如果失败,错误消息将包含模式和 text (或模式和 text *意外匹配的部分)。 * regex *可以是正则表达式对象,也可以是包含适合re.search()使用的正则表达式的字符串。

3.1 版的新Function:以名称assertRegexpMatches添加。

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

版本 3.2 中的新Function:assertNotRegex()

版本 3.5 中的新Function:名称assertNotRegexpMatchesassertNotRegex()的不赞成使用的别名。

  • assertCountEqual(* first second msg = None *)
    • 测试序列* first 包含与 second *相同的元素,而不管其 Sequences 如何。否则,将生成一条错误消息,列出序列之间的差异。

比较* first second *时,不会忽略重复的元素。它验证两个序列中每个元素的计数是否相同。等效于:assertEqual(Counter(list(first)), Counter(list(second))),但也适用于不可哈希对象序列。

3.2 版中的新Function。

assertEqual()方法将相同类型对象的相等性检查分派给不同类型特定的方法。这些方法已经为大多数内置类型实现,但是也可以使用addTypeEqualityFunc()注册新方法:

  • addTypeEqualityFunc(* typeobj function *)
    • 注册由assertEqual()调用的特定于类型的方法,以检查两个完全相同的* typeobj *(不是子类)的对象是否相等。Function必须接受两个位置参数,第三个 msg = None 关键字参数,就像assertEqual()一样。当检测到前两个参数之间的不平等时,它必须提高self.failureException(msg) -可能提供有用的信息并在错误消息中详细说明不平等。

3.1 版中的新Function。

下表总结了assertEqual()自动使用的特定于类型的方法的列表。请注意,通常不必直接调用这些方法。

Method 用于比较 New in
assertMultiLineEqual(a, b) strings 3.1
assertSequenceEqual(a, b) sequences 3.1
assertListEqual(a, b) lists 3.1
assertTupleEqual(a, b) tuples 3.1
assertSetEqual(a, b) 集或冻结集 3.1
assertDictEqual(a, b) dicts 3.1
  • assertMultiLineEqual(* first second msg = None *)
    • 测试多行字符串* first 等于字符串 second *。当不相等时,突出显示差异的两个字符串的差异将包含在错误消息中。比较字符串与assertEqual()时,默认使用此方法。

3.1 版中的新Function。

  • assertSequenceEqual((* first second msg = None seq_type = None *)
    • 测试两个序列是否相等。如果提供了* seq_type ,则 first second 都必须是 seq_type *的实例,否则将引发故障。如果 Sequences 不同,则会生成一条错误消息,显示两者之间的差异。

assertEqual()不会直接调用此方法,但是它用于实现assertListEqual()assertTupleEqual()

3.1 版中的新Function。

  • assertListEqual(* first second msg = None *)
    • assertTupleEqual(* first second msg = None *)
      • 测试两个列表或 Tuples 是否相等。如果不是,则构造一条错误消息,仅显示两者之间的差异。如果任何一个参数的类型错误,也会引发错误。将列表或 Tuples 与assertEqual()进行比较时,默认使用这些方法。

3.1 版中的新Function。

  • assertSetEqual(* first second msg = None *)
    • 测试两组是否相等。如果不是,则构造一条错误消息,列出这些组之间的差异。将集或冻结集与assertEqual()进行比较时,默认使用此方法。

如果* first second *都不具有set.difference()方法,则失败。

3.1 版中的新Function。

  • assertDictEqual(* first second msg = None *)
    • 测试两个字典是否相等。如果不是,则构造一条错误消息,显示字典中的差异。默认情况下,将使用此方法比较对assertEqual()的调用中的字典。

3.1 版中的新Function。

最后,TestCase提供以下方法和属性:

  • fail(* msg = None *)

    • 无条件地表示测试失败,错误消息带有* msg *或None
  • failureException

    • 此类属性给出了 test 方法引发的异常。如果测试框架需要使用特殊的异常(可能带有其他信息),则它必须将此异常子类化,以便与框架“公平竞争”。此属性的初始值为AssertionError
  • longMessage

    • 此类属性确定将自定义失败消息作为 msg 参数传递给失败的 assertXYY 调用时发生的情况。 True是默认值。在这种情况下,自定义消息将附加到标准失败消息的末尾。设置为False时,自定义消息将替换标准消息。

pass在调用 assert 方法之前将实例属性 self.longMessage 分配给TrueFalse,可以在各个测试方法中覆盖类设置。

每次测试调用之前,类设置都会重置。

3.1 版中的新Function。

maxDiff设置为None表示没有最大的差异长度。

3.2 版中的新Function。

测试框架可以使用以下方法来收集有关测试的信息:

  • countTestCases ( )

    • 返回此测试对象表示的测试数。对于TestCase个实例,它将始终为1
  • defaultTestResult ( )

    • 返回应用于此测试用例类的测试结果类的实例(如果未向run()方法提供其他结果实例)。

对于TestCase实例,它将始终是TestResult的实例; TestCase的子类应在必要时覆盖此子类。

  • id ( )

    • 返回标识特定测试用例的字符串。这通常是测试方法的全名,包括模块和类名。
  • shortDescription ( )

    • 返回测试的描述,如果未提供描述,则返回None。此方法的默认实现返回测试方法的文档字符串的第一行(如果有的话)或None

在版本 3.1 中进行了更改:在 3.1 中进行了更改,即使在存在文档字符串的情况下也将测试名称添加到简短描述中。这引起了与 unittest 扩展的兼容性问题,并且在 Python 3.2 中将测试名称添加到了TextTestResult

  • addCleanup((* function *, *args * kwargs *)
    • tearDown()之后添加一个要调用的函数,以清理测试期间使用的资源。将以与添加Function相反的 Sequences 调用这些Function(LIFO)。添加它们时,将使用传递到addCleanup()的任何参数和关键字参数来调用它们。

如果setUp()失败,即未调用tearDown(),则仍将调用添加的任何清除函数。

3.1 版中的新Function。

它负责调用addCleanup()添加的所有清除Function。如果您需要在tearDown()之前将清理Function称为* prior *,则可以自己调用doCleanups()

doCleanups()一次将一种方法从清除函数堆栈中弹出,因此可以随时调用它。

3.1 版中的新Function。

    • classmethod * addClassCleanup(* function /*, *args * kwargs *)
      • tearDownClass()之后添加一个要调用的函数,以清除测试类中使用的资源。将以与添加Function相反的 Sequences 调用这些Function(LIFO)。添加它们时,将使用传递到addClassCleanup()的任何参数和关键字参数来调用它们。

如果setUpClass()失败,即未调用tearDownClass(),则仍将调用添加的任何清除函数。

3.8 版的新Function。

它负责调用addCleanupClass()添加的所有清除函数。如果需要在tearDownClass()之前将清理Function称为* prior *,则可以自己调用doCleanupsClass()

doCleanupsClass()一次将一种方法从清除函数堆栈中弹出,因此可以随时调用它。

3.8 版的新Function。

    • class * unittest. IsolatedAsyncioTestCase(* methodName ='runTest'*)
    • 此类提供类似于TestCase的 API,并且也接受协程作为测试函数。

3.8 版的新Function。

  • 协程 asyncSetUp()

    • 调用准备测试夹具的方法。在setUp()之后调用。在调用测试方法之前立即调用该方法。除了AssertionErrorSkipTest之外,此方法引发的任何异常都将被视为错误而不是测试失败。默认实现不执行任何操作。
  • 协程 asyncTearDown()

    • 调用测试方法并记录结果后立即调用的方法。这称为tearDown()之前。即使测试方法引发异常,也会调用此方法,因此子类中的实现在检查内部状态时可能需要格外小心。除AssertionErrorSkipTest之外,此方法引发的任何异常都将被视为附加错误,而不是测试失败(因此会增加报告的错误总数)。无论asyncSetUp()成功如何,都将调用此方法,而不管测试方法的结果如何。默认实现不执行任何操作。
  • addAsyncCleanup((* function /*, *args * kwargs *)

    • 此方法接受可以用作清理Function的协程。
  • run(* result = None *)

    • 设置一个新的事件循环以运行测试,将结果收集到以* result 传递的TestResult对象中。如果Ellipsis result *或None,则会创建一个临时结果对象(pass调用defaultTestResult()方法)并使用它。结果对象将返回给run()的调用方。在测试结束时,事件循环中的所有任务都将被取消。

一个说明 Sequences 的示例:

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的测试框架中。

Deprecated aliases

由于历史原因,某些TestCase方法具有一个或多个别名,现在不建议使用。下表列出了正确的名称及其不赞成使用的别名:

Note

Method Name Deprecated alias Deprecated alias
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 *别名已被弃用。

从版本 3.2 开始不推荐使用:第三列中列出的 assert *别名已被弃用。

自版本 3.2 起不推荐使用:assertRegexpMatchesassertRaisesRegexp已重命名为assertRegex()assertRaisesRegex()

自版本 3.5 起不推荐使用:不推荐使用assertNotRegexpMatches名称,而推荐使用assertNotRegex()

Grouping tests

  • 类别 unittest. TestSuite(测试=())
    • 此类表示各个测试用例和测试套件的集合。该类提供测试运行程序所需的接口,以使其能够像其他任何测试用例一样运行。运行TestSuite实例与遍历套件(分别运行每个测试)相同。

如果给出* tests *,则它必须是单个测试用例或其他最初用于构建套件的测试套件的可迭代项。稍后提供了其他方法来将测试用例和套件添加到集合中。

TestSuite对象的行为与TestCase对象非常相似,不同之处在于它们实际上并未实施测试。相反,它们用于将测试聚合到应一起运行的测试组中。可以使用一些其他方法将测试添加到TestSuite实例:

这等效于迭代* tests *,对每个元素调用addTest()

TestSuiteTestCase共享以下方法:

  • run(结果)

    • 运行与此套件相关的测试,将结果收集到作为* result *传递的测试结果对象中。请注意,与TestCase.run()不同,TestSuite.run()要求传入结果对象。
  • debug ( )

    • 运行与此套件相关的测试,而不收集结果。这允许将测试引发的异常传播到调用方,并可用于支持在调试器下运行测试。
  • countTestCases ( )

    • 返回此测试对象表示的测试数量,包括所有单个测试和子套件。
  • __iter__ ( )

    • TestSuite分组的测试始终pass迭代访问。子类可以pass覆盖iter()懒惰地提供测试。请注意,在单个套件上可能多次调用了此方法(例如,在对测试计数或比较相等性时),因此在TestSuite.run()之前重复迭代返回的测试对于每个调用迭代必须相同。在TestSuite.run()之后,除非调用者使用重写TestSuite._removeTestAtIndex()的子类来保留测试引用,否则调用者不应依赖此方法返回的测试。

在 3.2 版中进行了更改:在较早的版本中,TestSuite直接访问测试而不是pass迭代访问,因此覆盖iter()不足以提供测试。

在版本 3.4 中进行了更改:在早期版本中,TestSuite保留对TestSuite.run()之后的每个TestCase的引用。子类可以pass覆盖TestSuite._removeTestAtIndex()来恢复该行为。

TestSuite对象的典型用法中,run()方法是由TestRunner而不是finally用户测试工具调用的。

加载和运行测试

  • 类别 unittest. TestLoader
    • TestLoader类用于从类和模块创建测试套件。通常,不需要创建此类的实例。 unittest模块提供了可以与unittest.defaultTestLoader共享的实例。但是,使用子类或实例可以自定义一些可配置的属性。

TestLoader个对象具有以下属性:

  • errors
    • 加载测试时遇到的非致命错误的列表。加载程序在任何时候都不会重置。致命错误pass相关的方法发出 signal,该方法向调用者引发异常。非致命错误还可以pass综合测试来指示,这将在运行时引发原始错误。

3.5 版中的新Function。

TestLoader对象具有以下方法:

  • loadTestsFromTestCase(* testCaseClass *)
    • 返回TestCase派生的testCaseClass中包含的所有测试用例的套件。

将为每个由getTestCaseNames()命名的方法创建一个测试用例实例。默认情况下,这些是以test开头的方法名称。如果getTestCaseNames()不返回任何方法,但是实现了runTest()方法,则将为该方法创建一个测试用例。

  • loadTestsFromModule(* module pattern = None *)
    • 返回给定模块中包含的所有测试用例的套件。此方法在* module *中搜索从TestCase派生的类,并为为该类定义的每个测试方法创建该类的实例。

Note

虽然使用TestCase派生的类的层次结构可以方便地共享固定装置和辅助函数,但是在不打算直接实例化的 Base Class 上定义测试方法在此方法中不能很好地发挥作用。但是,当固定装置不同且在子类中定义时,这样做可能会很有用。

如果模块提供load_tests函数,则将调用它以加载测试。这允许模块自定义测试加载。这是load_tests protocol。 * pattern *参数作为第三个参数传递给load_tests

在版本 3.2 中更改:添加了对load_tests的支持。

在版本 3.5 中进行了更改:不推荐使用非官方的非官方* use_load_tests 默认参数,尽管该参数仍为向后兼容而被接受。该方法现在还接受仅关键字参数 pattern *,该参数作为第三个参数传递给load_tests

  • loadTestsFromName(* name module = None *)
    • 给定字符串说明符,返回所有测试用例的套件。

说明符* name *是一个“点名”,可以解析为模块,测试用例类,测试用例类中的测试方法,TestSuite实例或返回TestCaseTestSuite实例的可调用对象。这些检查按照此处列出的 Sequences 进行;也就是说,可能的测试用例类上的方法将被选择为“测试用例类内的测试方法”,而不是“可调用对象”。

例如,如果您有一个包含TestCase派生类SampleTestCase的模块SampleTests以及三个测试方法(test_one()test_two()test_three()),则说明符'SampleTests.SampleTestCase'将导致此方法返回将运行所有三个测试方法的套件。使用说明符'SampleTests.SampleTestCase.test_two'将导致它返回仅运行test_two()测试方法的测试套件。该说明符可以引用尚未导入的模块和包。它们将作为副作用导入。

该方法可选地相对于给定的* module 解析 name *。

在版本 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 *)

    • pass从指定的开始目录递归到子目录中,找到所有测试模块,然后返回包含它们的 TestSuite 对象。仅加载与* pattern *匹配的测试文件。 (使用 Shell 样式模式匹配.)仅加载可导入的模块名称(即有效的 Python 标识符)。

所有测试模块必须可从项目的顶层导入。如果起始目录不是顶级目录,则必须单独指定顶级目录。

如果导入模块失败,例如由于语法错误,则将其记录为单个错误,并且发现将 continue。如果导入失败是由于引发SkipTest引起的,它将被记录为跳过而不是错误。

如果找到软件包(包含名为__init__.py的文件的目录),则将检查该软件包的load_tests函数。如果存在,则将其称为package.load_tests(loader, tests, pattern)。测试发现要小心确保即使在 load_tests 函数本身调用loader.discover的情况下,在调用过程中仅对程序包检查一次测试。

如果load_tests存在,则发现不会递归到软件包中,load_tests负责将软件包中的所有测试加载。

故意不将模式存储为 loader 属性,以便程序包可以自己 continue 发现。 * top_level_dir *已存储,因此load_tests无需将此参数传递给loader.discover()

  • start_dir *可以是点分模块名称以及目录。

3.2 版中的新Function。

在版本 3.4 中进行了更改:在导入时引发SkipTest的模块记录为跳过而不是错误。发现适用于namespace packages。在导入之前对路径进行排序,以便即使基础文件系统的 Sequences 不依赖于文件名,执行 Sequences 也相同。

在版本 3.5 中进行了更改:现在,无论路径是否匹配* pattern *,都将检查找到的软件包中的load_tests,因为软件包名称不可能与默认模式匹配。

TestLoader的以下属性可以pass子类化或在实例上分配来配置:

  • testMethodPrefix
    • 字符串,提供方法名称的前缀,该名称将被解释为测试方法。默认值为'test'

这会影响getTestCaseNames()和所有loadTestsFrom*()方法。

  • sortTestMethodsUsing

    • getTestCaseNames()和所有loadTestsFrom*()方法中对方法名称进行排序时用于比较方法名称的函数。
  • suiteClass

    • 从测试列表构造测试套件的可调用对象。在结果对象上不需要任何方法。默认值为TestSuite类。

这会影响所有loadTestsFrom*()方法。

  • testNamePatterns
    • 测试方法必须匹配才能包含在测试套件中的 Unix shell 样式通配符测试名称模式的列表(请参见-v选项)。

如果此属性不是None(默认值),则要包含在测试套件中的所有测试方法必须与该列表中的模式之一匹配。请注意,匹配始终使用fnmatch.fnmatchcase()执行,因此与传递给-v选项的模式不同,必须使用*通配符转换简单的子字符串模式。

这会影响所有loadTestsFrom*()方法。

3.7 版中的新Function。

  • 类别 unittest. TestResult
    • 此类用于编译有关哪些测试成功和失败的信息。

TestResult对象存储一组测试的结果。 TestCaseTestSuite类可确保正确记录结果;测试作者无需担心记录测试结果。

构建在unittest之上的测试框架可能希望访问pass运行一组测试生成的TestResult对象以进行报告。为此,TestRunner.run()方法返回一个TestResult实例。

TestResult实例具有以下属性,这些属性在检查运行一组测试的结果时会引起关注:

  • errors

    • 包含 2 个 Tuples 的TestCase实例和包含格式化回溯的字符串的列表。每个 Tuples 代表一个引发意外异常的测试。
  • failures

    • 包含 2 个 Tuples 的TestCase实例和包含格式化回溯的字符串的列表。每个 Tuples 代表一个测试,在该测试中使用TestCase.assert*()方法明确指示了失败。
  • skipped

    • 包含 2 个 Tuples 的TestCase实例和字符串的列表,其中包含跳过测试的原因。

3.1 版中的新Function。

  • expectedFailures

    • 包含 2 个 Tuples 的TestCase实例和包含格式化回溯的字符串的列表。每个 Tuples 代表测试用例的预期失败。
  • unexpectedSuccesses

    • 包含TestCase个实例的列表,这些实例被标记为预期失败,但已成功。
  • shouldStop

    • 当测试执行应在stop()停止时设置为True
  • testsRun

    • 到目前为止,测试总数。
  • buffer

    • 如果设置为 true,则sys.stdoutsys.stderr将被缓冲在被调用的startTest()stopTest()之间。如果测试失败或错误,则仅将收集的输出回显到实际的sys.stdoutsys.stderr上。任何输出也将附加到失败/错误消息。

3.2 版中的新Function。

  • failfast
    • 如果设置为 true,则在第一次失败或错误时会调用stop(),从而暂停测试运行。

3.2 版中的新Function。

  • tb_locals
    • 如果设置为 true,则局部变量将在回溯中显示。

3.5 版中的新Function。

  • wasSuccessful ( )
    • 如果到目前为止运行的所有测试均已pass,则返回True,否则返回False

在版本 3.4 中更改:如果标记为expectedFailure()装饰器的测试中有unexpectedSuccesses,则返回False

  • stop ( )
    • pass将shouldStop属性设置为True,可以调用此方法来表明正在运行的测试集应中止。 TestRunner对象应遵守此标志并在不运行任何其他测试的情况下返回。

例如,当用户从键盘发出break signal 时,TextTestRunner类将使用此Function来停止测试框架。提供TestRunner实现的交互式工具可以类似的方式使用它。

TestResult类的以下方法用于维护内部数据结构,并且可以在子类中扩展以支持其他报告要求。这对于在运行测试时支持交互式报告的构建工具特别有用。

  • startTest(测试)

    • 在将要运行测试用例* test *时调用。
  • stopTest(测试)

    • 在测试用例* test *执行完毕后调用,无论结果如何。
  • startTestRun ( )

    • 在执行任何测试之前调用一次。

3.1 版中的新Function。

  • stopTestRun ( )
    • 执行完所有测试后调用一次。

3.1 版中的新Function。

  • addError(* test err *)
    • 当测试用例* test *引发意外异常时调用。 * err *是sys.exc_info()(type, value, traceback)返回的形式的 Tuples。

默认实现将 Tuples(test, formatted_err)附加到实例的errors属性,其中* formatted_err 是从 err *派生的格式化回溯。

  • addFailure(* test err *)
    • 当测试用例* test *发出故障 signal 时调用。 * err *是sys.exc_info()(type, value, traceback)返回的形式的 Tuples。

默认实现将 Tuples(test, formatted_err)附加到实例的failures属性,其中* formatted_err 是从 err *派生的格式化回溯。

  • addSuccess(测试)
    • 在测试用例* test *成功时调用。

默认实现不执行任何操作。

  • addSkip(* test reason *)
    • 当测试用例* test *被跳过时调用。 原因是测试给出跳过的原因。

默认实现将 Tuples(test, reason)附加到实例的skipped属性。

  • addExpectedFailure(* test err *)

默认实现将 Tuples(test, formatted_err)附加到实例的expectedFailures属性,其中* formatted_err 是从 err *派生的格式化回溯。

  • addUnexpectedSuccess(测试)

默认实现将测试附加到实例的unexpectedSuccesses属性。

  • addSubTest((* test subtest *,成果)
    • 子测试完成时调用。 * test *是与测试方法相对应的测试用例。 * subtest *是描述子测试的自定义TestCase实例。

如果结果None,则子测试成功。否则,它会失败,并发生以下异常:结果sys.exc_info()(type, value, traceback)返回的形式的 Tuples。

结果成功时,默认实现不执行任何操作,并将子测试失败记录为正常失败。

3.4 版的新Function。

    • class * unittest. TextTestResult(* stream descriptions verbosity *)

版本 3.2 中的新Function:此类以前称为_TextTestResult。旧名称仍然作为别名存在,但已过时。

  • unittest. defaultTestLoader

    • 打算共享的TestLoader类的实例。如果不需要自定义TestLoader,则可以使用此实例,而不必重复创建新实例。
    • class * unittest. TextTestRunner(* stream = None descriptions = True verbosity = 1 failfast = False buffer = False resultclass = None warnings = None * tb_locals = False *)
    • 将结果输出到流的基本测试运行器实现。如果* stream *为None,则默认值sys.stderr用作输出流。此类具有一些可配置的参数,但本质上非常简单。运行测试套件的图形应用程序应提供替代的实现。当将Function添加到单元测试时,此类实现应接受**kwargs作为构造运行程序的接口。

默认情况下,该 Running 者显示DeprecationWarningPendingDeprecationWarningResourceWarningImportWarning,即使他们是默认情况下被忽略。由不推荐使用的单元测试方法引起的弃用警告也是特殊情况,当警告过滤器为'default''always'时,每个模块将仅出现一次,以避免过多的警告消息。可以使用 Python 的-Wd-Wa选项(请参见Warning control)并将* warnings *留给None来覆盖此行为。

在版本 3.2 中更改:添加了warnings参数。

在版本 3.2 中更改:默认流在实例化时间而不是导入时间设置为sys.stderr

在版本 3.5 中进行了更改:添加了 tb_locals 参数。

  • _makeResult ( )
    • 此方法返回run()使用的TestResult实例。它不打算直接调用,但是可以在子类中重写以提供自定义TestResult

_makeResult()实例化TextTestRunner构造函数中作为resultclass参数传递的类或可调用对象。如果未提供resultclass,则默认为TextTestResult。结果类使用以下参数实例化:

stream, descriptions, verbosity
  • run(测试)

  • 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 *加载一组测试并运行它们;这主要是为了使测试模块方便执行。此Function最简单的用法是在测试脚本的末尾包含以下行:
if __name__ == '__main__':
    unittest.main()

您可以pass传入 verbosity 参数来运行包含更详细信息的测试:

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

如果没有pass* argv 指定测试名称,则 defaultTest 参数要么是单个测试的名称,要么是要运行的测试名称的可迭代名称。如果未指定或None并且没有pass argv 提供测试名称,则将运行 module *中找到的所有测试。

  • argv *参数可以是传递给程序的选项列表,第一个元素是程序名称。如果未指定或None,则使用sys.argv的值。

  • testRunner *参数可以是测试运行器类,也可以是已经创建的实例。默认情况下,main调用sys.exit()并带有退出代码,以指示测试运行成功或失败。

  • testLoader *参数必须是TestLoader实例,默认为defaultTestLoader

main支持pass传入参数exit=False从交互式解释器中使用。这将在标准输出上显示结果,而无需调用sys.exit()

>>> from unittest import main
>>> main(module='test_module', exit=False)
  • failfast catchbreak buffer *参数的作用与同名command-line options相同。

  • warnings *参数指定运行测试时应使用的warning filter。如果未指定,则将-W选项传递给 python (请参见Warning control),它将保留None,否则将其设置为'default'

调用main实际上会返回TestProgram类的实例。这会将测试结果存储为result属性。

在版本 3.1 中更改:添加了* exit *参数。

在版本 3.2 中更改:添加了* verbosity failfast catchbreak buffer warnings *参数。

在版本 3.4 中进行了更改:* defaultTest *参数已更改为还接受可迭代的测试名称。

load_tests Protocol

3.2 版中的新Function。

模块或软件包可以pass实现称为load_tests的Function来自定义在正常测试运行或测试发现期间如何从中加载测试。

如果测试模块定义了load_tests,它将由TestLoader.loadTestsFromModule()调用,并带有以下参数:

load_tests(loader, standard_tests, pattern)
  • pattern *从loadTestsFromModule直接pass。默认为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

如果从命令行或pass调用TestLoader.discover()在包含软件包的目录中启动发现,则将在软件包__init__.py中检查load_tests。如果该Function不存在,发现将被递归到软件包中,就好像它只是另一个目录一样。否则,包测试的发现将留给load_tests,它使用以下参数调用:

load_tests(loader, standard_tests, pattern)

这应该返回一个TestSuite,代表该程序包中的所有测试。 (standard_tests仅包含从__init__.py收集的测试.)

由于该模式已传递到load_tests中,因此程序包可以自由 continue(并可能修改)测试发现。测试包的“不执行任何操作” 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

完成所有测试后,将运行finally的tearDownClasstearDownModule

请注意,共享夹具不能与测试并行化等[潜在]Function配合使用,并且会破坏测试隔离。应该小心使用它们。

由 unittest 测试加载程序创建的测试的默认 Sequences 是将来自相同模块和类的所有测试组合在一起。这将导致每个类和模块一次调用setUpClass/setUpModule(等)。如果您将 Sequences 随机化,以使来自不同模块和类的测试彼此相邻,则可以在一次测试运行中多次调用这些共享的夹具Function。

共享夹具不适用于非标准 Order 的套件。 BaseTestSuite对于不希望支持共享装置的框架仍然存在。

如果在共享夹具Function之一期间引发任何异常,则将测试报告为错误。因为没有相应的测试实例,所以创建了_ErrorHolder对象(与TestCase具有相同的接口)来表示错误。如果您只是使用标准的单元测试测试运行程序,那么此细节并不重要,但是如果您是框架作者,则可能很重要。

setUpClass 和 tearDownClass

这些必须作为类方法实现:

import unittest

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

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

如果要在 Base Class 上调用setUpClasstearDownClass,则必须自己调用它们。 TestCase中的实现为空。

如果在setUpClass期间引发异常,则不会运行该类中的测试,也不会运行tearDownClass。跳过的类不会运行setUpClasstearDownClass。如果该异常是SkipTest异常,则该类将被报告为已跳过而不是错误。

setUpModule 和 tearDownModule

这些应实现为Function:

def setUpModule():
    createConnection()

def tearDownModule():
    closeConnection()

如果setUpModule中引发异常,则模块中的任何测试都不会运行,而tearDownModule也不会运行。如果异常是SkipTest异常,则模块将被报告为已跳过而不是错误。

要添加即使在发生异常情况下也必须运行的清除代码,请使用addModuleCleanup

  • unittest. addModuleCleanup(* function /*, *args * kwargs *)
    • tearDownModule()之后添加一个要调用的函数,以清除测试类中使用的资源。将以与添加Function相反的 Sequences 调用这些Function(LIFO)。添加它们时,将使用传递到addModuleCleanup()的任何参数和关键字参数来调用它们。

如果setUpModule()失败,即未调用tearDownModule(),则仍将调用添加的任何清除函数。

3.8 版的新Function。

  • unittest. doModuleCleanups ( )
    • 如果setUpModule()引发异常,则在tearDownModule()之后或setUpModule()之后无条件调用此函数。

它负责调用addCleanupModule()添加的所有清除函数。如果需要在tearDownModule()之前将清理Function称为* pri *,则可以自己调用doModuleCleanups()

doModuleCleanups()一次将一种方法从清除函数堆栈中弹出,因此可以随时调用它。

3.8 版的新Function。

Signal Handling

3.2 版中的新Function。

单元测试的-c/--catch命令行选项,以及unittest.main()catchbreak参数,在测试运行期间提供了对 Control-C 的更友好处理。启用捕获break行为后,control-C 将允许当前运行的测试完成,然后测试运行将结束并报告到目前为止的所有结果。第二个 Control-c 将以通常方式提高KeyboardInterrupt

控件 c 处理 signal 处理程序try与安装自己的signal.SIGINT处理程序的代码或测试保持兼容。如果调用unittest处理程序但不是*已安装的signal.SIGINT处理程序,即它已被测试系统替换并委托给它,则它将调用默认处理程序。pass替换已安装的处理程序并委托给它的代码,这通常是预期的行为。对于需要禁用unittest control-c 处理的单个测试,可以使用removeHandler()装饰器。

有一些 Util Function可供框架作者使用,以在测试框架中启用 Control-C 处理Function。

  • unittest. installHandler ( )

    • 安装 control-c 处理程序。当收到signal.SIGINT时(通常是响应用户按下 Ctrl-c),所有已注册的结果都被调用stop()
  • unittest. registerResult(结果)

    • 注册TestResult对象以进行 Control-C 处理。注册结果会对其存储一个弱引用,因此不会阻止结果被垃圾收集。

如果未启用 control-c 处理,则注册TestResult对象没有副作用,因此测试框架可以无条件地注册其创建的所有结果,而与是否启用处理无关。

  • unittest. removeResult(结果)

    • 删除注册结果。删除结果后,将不再响应该 Control-c 在该结果对象上调用stop()
  • unittest. removeHandler(* function = None *)

    • 如果不带参数调用此函数,则会删除 Control-C 处理程序(如果已安装)。此函数还可以用作测试装饰器,以在执行测试时临时删除处理程序:
@unittest.removeHandler
def test_signal_handling(self):
    ...