unittest — 单元测试框架 — Python 文档

来自菜鸟教程
Python/docs/3.7/library/unittest
跳转至:导航、​搜索

unittest — 单元测试框架

源代码: :source:`Lib/unittest/__init__.py`



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

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

为了实现这一点,unittest 以面向对象的方式支持一些重要的概念:

测试夹具
测试装置 表示执行一个或多个测试所需的准备工作,以及任何相关的清理操作。 例如,这可能涉及创建临时或代理数据库、目录或启动服务器进程。
测试用例
测试用例 是单独的测试单元。 它检查对特定输入集的特定响应。 unittest 提供了一个基类,TestCase,可用于创建新的测试用例。
测试套件
测试套件 是测试用例、测试套件或两者的集合。 它用于聚合应该一起执行的测试。
测试运行器
测试运行器 是一个组件,用于协调测试的执行并向用户提供结果。 运行器可以使用图形界面、文本界面或返回一个特殊值来指示执行测试的结果。

也可以看看

模块 doctest
另一个具有非常不同风格的测试支持模块。
简单的 Smalltalk 测试:使用模式
Kent Beck 关于使用 unittest 共享模式的测试框架的原始论文。
pytest
第三方单元测试框架,具有用于编写测试的轻量级语法。 例如,assert func(10) == 42
Python 测试工具分类法
Python 测试工具的广泛列表,包括功能测试框架和模拟对象库。
在 Python 邮件列表中测试
在 Python 中讨论测试和测试工具的特殊兴趣小组。

Python源代码分发中的脚本Tools/unittestgui/unittestgui.py是一个用于测试发现和执行的GUI工具。 这主要是为了便于那些不熟悉单元测试的人使用。 对于生产环境,建议测试由持续集成系统驱动,例如 BuildbotJenkinsHudson


基本示例

unittest 模块提供了一套丰富的工具来构建和运行测试。 本节展示了一小部分工具足以满足大多数用户的需求。

这是测试三个字符串方法的简短脚本:

import unittest

class TestStringMethods(unittest.TestCase):

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

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

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

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

测试用例是通过子类化 unittest.TestCase 创建的。 这三个单独的测试是用名称以字母 test 开头的方法定义的。 此命名约定通知测试运行器哪些方法代表测试。

每个测试的关键是调用 assertEqual() 以检查预期结果; assertTrue()assertFalse() 验证条件; 或 assertRaises() 以验证是否引发了特定异常。 这些方法用于代替 assert 语句,因此测试运行器可以累积所有测试结果并生成报告。

setUp()tearDown() 方法允许您定义将在每个测试方法之前和之后执行的指令。 它们在 组织测试代码 部分有更详细的介绍。

最后一个块显示了运行测试的简单方法。 unittest.main() 为测试脚本提供命令行界面。 从命令行运行时,上面的脚本会生成如下所示的输出:

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

OK

-v 选项传递给您的测试脚本将指示 unittest.main() 启用更高级别的详细信息,并产生以下输出:

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

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

OK

上面的例子展示了最常用的 unittest 特性,这些特性足以满足许多日常测试需求。 文档的其余部分从首要原则探索了完整的功能集。


命令行界面

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

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

您可以传入包含模块名称和完全限定类或方法名称的任意组合的列表。

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

python -m unittest tests/test_something.py

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

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

python -m unittest -v test_module

当不带参数执行时 Test Discovery 启动:

python -m unittest

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

python -m unittest -h

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


命令行选项

unittest 支持这些命令行选项:

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

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

有关提供此功能的函数,请参阅 信号处理

-f, --failfast
在第一个错误或失败时停止测试运行。
-k

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

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

模式与测试加载器导入的完全限定的测试方法名称匹配。

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

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

3.2 新功能: 添加了命令行选项 -b-c-f


3.5 新功能:命令行选项--locals


3.7 版新功能:命令行选项-k


命令行也可用于测试发现、运行项目中的所有测试或仅运行一个子集。


测试发现

3.2 版中的新功能。


Unittest 支持简单的测试发现。 为了兼容测试发现,所有的测试文件必须是 modulespackages(包括 namespace packages),可以从项目(这意味着它们的文件名必须是有效的 标识符 )。

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

cd project_directory
python -m unittest discover

笔记

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


discover 子命令有以下选项:

-v, --verbose
详细输出
-s, --start-directory directory
开始发现的目录(. 默认)
-p, --pattern pattern
匹配测试文件的模式(test*.py 默认)
-t, --top-level-directory directory
项目的顶级目录(默认为启动目录)

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

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

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

警告

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

如果您有一个全局安装的软件包并尝试在该软件包的不同副本上进行测试发现,那么导入 ' 可能发生在错误的位置。 如果发生这种情况,测试发现将警告您并退出。

如果您将起始目录作为包名而不是目录路径提供,那么discover 假定它从哪个位置导入就是您想要的位置,因此您不会收到警告。


测试模块和包可以通过load_tests协议自定义测试加载和发现。

3.4 版更改: 测试发现支持 命名空间包


组织测试代码

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

请注意,为了测试某些内容,我们使用 TestCase 基类提供的 assert*() 方法之一。 如果测试失败,将引发带有解释性消息的异常,并且 unittest 会将测试用例标识为 failure。 任何其他异常将被视为 错误

测试可能很多,并且它们的设置可能是重复的。 幸运的是,我们可以通过实现一个名为 setUp() 的方法来分解设置代码,测试框架会为我们运行的每个测试自动调用它:

import unittest

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

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

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

笔记

运行各种测试的顺序是通过根据字符串的内置顺序对测试方法名称进行排序来确定的。


如果在测试运行时 setUp() 方法引发异常,框架将认为测试发生了错误,并且不会执行测试方法。

同样,我们可以提供一个 tearDown() 方法,在测试方法运行后进行整理:

import unittest

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

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

如果 setUp() 成功,无论测试方法成功与否,都会运行 tearDown()

这种用于测试代码的工作环境称为 测试装置 。 创建一个新的 TestCase 实例作为唯一的测试装置,用于执行每个单独的测试方法。 因此,每次测试将调用 setUp()tearDown()__init__() 一次。

建议您使用 TestCase 实现根据测试的功能将测试组合在一起。 unittest为此提供了一种机制:测试套件,由unittestTestSuite类表示。 在大多数情况下,调用 unittest.main() 会做正确的事情并为您收集模块的所有测试用例并执行它们。

但是,如果您想自定义测试套件的构建,您可以自己完成:

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

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

您可以将测试用例和测试套件的定义放在与它们要测试的代码相同的模块中(例如 widget.py),但是将测试代码放在单独的模块中有几个优点,例如test_widget.py

  • 测试模块可以从命令行独立运行。
  • 测试代码可以更容易地从交付的代码中分离出来。
  • 在没有充分理由的情况下更改测试代码以适应它测试的代码的诱惑较小。
  • 测试代码的修改频率应该远低于它测试的代码。
  • 可以更轻松地重构经过测试的代码。
  • 无论如何,用 C 编写的模块的测试必须在单独的模块中,那么为什么不保持一致呢?
  • 如果测试策略发生变化,则无需更改源代码。


重用旧的测试代码

一些用户会发现他们有现有的测试代码,他们希望从 unittest 运行,而无需将每个旧的测试函数转换为 TestCase 子类。

为此,unittest 提供了一个 FunctionTestCase 类。 TestCase 的这个子类可用于包装现有的测试函数。 还可以提供设置和拆卸功能。

给定以下测试函数:

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

可以创建一个等效的测试用例实例,如下所示,具有可选的设置和拆卸方法:

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

笔记

尽管 FunctionTestCase 可用于将现有测试库快速转换为基于 unittest 的系统,但不推荐这种方法。 花时间设置适当的 TestCase 子类将使未来的测试重构变得更加容易。


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


跳过测试和预期失败

3.1 版中的新功能。


Unittest 支持跳过单个测试方法甚至整个测试类。 此外,它还支持将测试标记为“预期失败”,该测试被破坏并将失败,但不应在 TestResult 上被视为失败。

跳过测试只是使用 skip() 装饰器 或其条件变体之一,在 中调用 TestCase.skipTest() setUp() 或测试方法,或直接提高 SkipTest

基本跳过看起来像这样:

class MyTestCase(unittest.TestCase):

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

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

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

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

这是在详细模式下运行上述示例的输出:

test_format (__main__.MyTestCase) ... 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")

通过在测试中调用 skip() 的装饰器,当它想要被跳过时,很容易滚动你自己的跳过装饰器。 除非传递的对象具有特定属性,否则此装饰器会跳过测试:

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

以下装饰器和异常实现了测试跳过和预期失败:

@unittest.skip(reason)
无条件跳过装饰测试。 reason 应该描述跳过测试的原因。
@unittest.skipIf(condition, reason)
如果 condition 为真,则跳过装饰测试。
@unittest.skipUnless(condition, reason)
跳过装饰测试,除非 condition 为真。
@unittest.expectedFailure
将测试标记为预期失败。 如果测试失败,则视为成功。 如果测试通过,将被视为失败。
exception unittest.SkipTest(reason)

引发此异常以跳过测试。

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

跳过的测试不会有 setUp()tearDown() 围绕它们运行。 跳过的课程将不会运行 setUpClass()tearDownClass()。 跳过的模块将不会运行 setUpModule()tearDownModule()


使用子测试区分测试迭代

3.4 版中的新功能。


当您的测试之间存在非常小的差异时,例如某些参数,unittest 允许您使用 subTest() 上下文管理器在测试方法的主体内区分它们。

例如,下面的测试:

class NumbersTest(unittest.TestCase):

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

将产生以下输出:

======================================================================
FAIL: test_even (__main__.NumbersTest) (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。

测试用例

class unittest.TestCase(methodName='runTest')

TestCase 类的实例代表 unittest 宇宙中的逻辑测试单元。 此类旨在用作基类,具体测试由具体子类实现。 此类实现了测试运行程序所需的接口以允许它驱动测试,以及测试代码可用于检查和报告各种故障的方法。

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

3.2 版更改: TestCase 可以在不提供 methodName 的情况下成功实例化。 这使得从交互式解释器中试验 TestCase 变得更加容易。

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

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

setUp()

调用方法来准备测试夹具。 这是在调用测试方法之前立即调用的; 除了 AssertionErrorSkipTest,此方法引发的任何异常都将被视为错误而不是测试失败。 默认实现什么都不做。

tearDown()

在调用测试方法并记录结果后立即调用方法。 即使测试方法引发异常也会调用它,因此子类中的实现可能需要特别小心检查内部状态。 除 AssertionErrorSkipTest 之外的任何异常,由该方法引发的将被视为额外错误而不是测试失败(从而增加报告错误的总数)。 无论测试方法的结果如何,仅当 setUp() 成功时才会调用此方法。 默认实现什么都不做。

setUpClass()

在运行单个类中的测试之前调用的类方法。 setUpClass 以类作为唯一参数被调用,并且必须装饰为 classmethod()

@classmethod
def setUpClass(cls):
    ...

有关更多详细信息,请参阅 类和模块装置

3.2 版中的新功能。

tearDownClass()

在单个类中的测试运行后调用的类方法。 tearDownClass 以类作为唯一参数被调用,并且必须装饰为 classmethod()

@classmethod
def tearDownClass(cls):
    ...

有关更多详细信息,请参阅 类和模块装置

3.2 版中的新功能。

run(result=None)

运行测试,将结果收集到作为 result 传递的 TestResult 对象中。 如果省略 resultNone,则创建一个临时结果对象(通过调用 defaultTestResult() 方法)并使用。 结果对象返回给 run() 的调用者。

简单地调用 TestCase 实例也可以产生同样的效果。

3.3 版更改: run 之前的版本没有返回结果。 也没有调用实例。

skipTest(reason)

在测试方法或 setUp() 期间调用它会跳过当前测试。 有关更多信息,请参阅 跳过测试和预期失败

3.1 版中的新功能。

subTest(msg=None, **params)

返回一个上下文管理器,它执行封闭的代码块作为子测试。 msgparams 是可选的任意值,当子测试失败时会显示这些值,让您可以清楚地识别它们。

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

有关详细信息,请参阅 使用子测试区分测试迭代

3.4 版中的新功能。

debug()

运行测试而不收集结果。 这允许将测试引发的异常传播给调用者,并可用于支持在调试器下运行测试。

TestCase 类提供了几种断言方法来检查和报告失败。 下表列出了最常用的方法(更多断言方法见下表):

方法

检查

新进

assertEqual(a, b)

a == b

assertNotEqual(a, b)

a != b

assertTrue(x)

bool(x) is True

assertFalse(x)

bool(x) is False

assertIs(a, b)

a is b

3.1

assertIsNot(a, b)

a is not b

3.1

assertIsNone(x)

x is None

3.1

assertIsNotNone(x)

x is not None

3.1

assertIn(a, b)

a in b

3.1

assertNotIn(a, b)

a not in b

3.1

assertIsInstance(a, b)

isinstance(a, b)

3.2

assertNotIsInstance(a, b)

not isinstance(a, b)

3.2

所有断言方法都接受一个 msg 参数,如果指定,则用作失败时的错误消息(另见 longMessage)。 注意 msg 关键字参数可以传递给 assertRaises(), assertRaisesRegex(), assertWarns(), assertWarns () 仅当它们用作上下文管理器时。

assertEqual(first, second, msg=None)

测试 firstsecond 是否相等。 如果比较的值不相等,则测试将失败。

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

3.1 版本更改: 增加了类型特定相等函数的自动调用。

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

assertNotEqual(first, second, msg=None)

测试 firstsecond 不相等。 如果值比较相等,则测试将失败。

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

测试 expr 为真(或假)。

请注意,这相当于 bool(expr) is True 而不是 expr is True(后者使用 assertIs(expr, True))。 当有更具体的方法可用时,也应避免使用此方法(例如 assertEqual(a, b) 而不是 assertTrue(a == b)),因为它们在发生故障时提供了更好的错误消息。

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

测试 firstsecond 对同一个对象求值(或不求值)。

3.1 版中的新功能。

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

测试 expr 是(或不是)None

3.1 版中的新功能。

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

测试 member 是否在 容器 中。

3.1 版中的新功能。

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

测试 obj 是(或不是)cls 的实例(可以是一个类或类的元组,由 isinstance() 支持) . 要检查确切的类型,请使用 assertIs(type(obj), cls)

3.2 版中的新功能。

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

方法

检查

新进

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

fun(*args, **kwds) 提升 exc

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

fun(*args, **kwds) 引发 exc 并且消息匹配正则表达式 r

3.1

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

fun(*args, **kwds) 引发 warn

3.2

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

fun(*args, **kwds) 引发 warn 并且消息匹配正则表达式 r

3.2

assertLogs(logger, level)

with 块以最低 级别 登录 logger

3.4

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

测试当使用任何位置或关键字参数调用 callable 时是否引发异常,这些参数也传递给 assertRaises()。 如果引发 exception,则测试通过,如果引发另一个异常,则测试为错误,如果未引发异常,则测试失败。 要捕获一组异常中的任何一个,可以将包含异常类的元组作为 exception 传递。

如果只给出了 exception 和可能的 msg 参数,则返回一个上下文管理器,以便被测代码可以内联而不是作为函数编写:

with self.assertRaises(SomeException):
    do_something()

当用作上下文管理器时,assertRaises() 接受额外的关键字参数 msg

上下文管理器会将捕获的异常对象存储在其 exception 属性中。 如果目的是对引发的异常执行额外检查,这可能很有用:

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

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

3.1 版更改: 添加了使用 assertRaises() 作为上下文管理器的功能。

3.2 版更改: 添加 exception 属性。

在 3.3 版更改: 在用作上下文管理器时添加了 msg 关键字参数。

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

assertRaises() 类似,但也测试 regex 是否与引发异常的字符串表示匹配。 regex 可以是正则表达式对象,也可以是包含适合 re.search() 使用的正则表达式的字符串。 例子:

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

或者:

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

3.1 版新功能:assertRaisesRegexp 名称添加。

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

在 3.3 版更改: 在用作上下文管理器时添加了 msg 关键字参数。

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

测试当使用任何位置或关键字参数调用 callable 时触发警告,这些参数也传递给 assertWarns()。 如果触发了 warning,则测试通过,否则测试失败。 任何异常都是错误。 要捕获一组警告中的任何一个,可以将包含警告类的元组作为 warnings 传递。

如果只给出了 warning 和可能的 msg 参数,则返回一个上下文管理器,以便被测代码可以内联而不是作为函数编写:

with self.assertWarns(SomeWarning):
    do_something()

当用作上下文管理器时,assertWarns() 接受额外的关键字参数 msg

上下文管理器会将捕获的警告对象存储在其 warning 属性中,并将触发警告的源代码行存储在 filenamelineno 属性中。 如果目的是对捕获的警告执行额外检查,这可能很有用:

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

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

无论调用时是否有警告过滤器,此方法都有效。

3.2 版中的新功能。

在 3.3 版更改: 在用作上下文管理器时添加了 msg 关键字参数。

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

assertWarns() 类似,但也测试 regex 是否与触发警告的消息匹配。 regex 可以是正则表达式对象,也可以是包含适合 re.search() 使用的正则表达式的字符串。 例子:

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

或者:

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

3.2 版中的新功能。

在 3.3 版更改: 在用作上下文管理器时添加了 msg 关键字参数。

assertLogs(logger=None, level=None)

一个上下文管理器,用于测试至少有一条消息记录在 logger 或其子节点之一上,至少具有给定的 级别

如果给出, logger 应该是一个 logging.Logger 对象或一个 str 给出记录器的名称。 默认是根记录器,它将捕获所有消息。

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

如果 with 块内发出的至少一条消息与 loggerlevel 条件匹配,则测试通过,否则失败。

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

records

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

output

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

例子:

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

3.4 版中的新功能。

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

方法

检查

新进

assertAlmostEqual(a, b)

round(a-b, 7) == 0

assertNotAlmostEqual(a, b)

round(a-b, 7) != 0

assertGreater(a, b)

a > b

3.1

assertGreaterEqual(a, b)

a >= b

3.1

assertLess(a, b)

a < b

3.1

assertLessEqual(a, b)

a <= b

3.1

assertRegex(s, r)

r.search(s)

3.1

assertNotRegex(s, r)

not r.search(s)

3.2

assertCountEqual(a, b)

ab 具有相同数量的相同元素,无论它们的顺序如何。

3.2

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

通过计算差值来测试 firstsecond 是否近似(或不近似)相等,四舍五入到给定的小数位数 places(默认为 7),以及与零相比。 请注意,这些方法将值四舍五入到给定的 小数位数 (即 像 round() 函数)而不是 有效数字

如果提供 delta 而不是 places,则 firstsecond 之间的差异必须小于或等于(或大于)[ X163X]delta。

提供 deltaplaces 会引发 TypeError

3.2 版更改: assertAlmostEqual() 自动考虑比较相等的几乎相等的对象。 assertNotAlmostEqual() 如果对象比较相等,则自动失败。 添加了 delta 关键字参数。

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

测试一下第一的分别是 >、>=、< 或 <= 比第二取决于方法名称。 如果没有,测试将失败:

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

3.1 版中的新功能。

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

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

3.1 版新功能:assertRegexpMatches 名称添加。

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

3.2 版新功能:assertNotRegex()

3.5 版新功能: 名称 assertNotRegexpMatchesassertNotRegex() 的弃用别名。

assertCountEqual(first, second, msg=None)

测试序列 first 包含与 second 相同的元素,无论它们的顺序如何。 如果他们不这样做,则会生成一条错误消息,列出序列之间的差异。

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

3.2 版中的新功能。

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

addTypeEqualityFunc(typeobj, function)

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

3.1 版中的新功能。

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

方法

用来比较

新进

assertMultiLineEqual(a, b)

字符串

3.1

assertSequenceEqual(a, b)

序列

3.1

assertListEqual(a, b)

列表

3.1

assertTupleEqual(a, b)

元组

3.1

assertSetEqual(a, b)

集或冻结集

3.1

assertDictEqual(a, b)

听写

3.1

assertMultiLineEqual(first, second, msg=None)

测试多行字符串 first 是否等于字符串 second。 当不相等时,突出显示差异的两个字符串的差异将包含在错误消息中。 在将字符串与 assertEqual() 进行比较时,默认使用此方法。

3.1 版中的新功能。

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

测试两个序列是否相等。 如果提供了 seq_type,则 firstsecond 都必须是 seq_type 的实例,否则将引发故障。 如果序列不同,则会构建一条错误消息,显示两者之间的差异。

这个方法不是直接被assertEqual()调用,而是用来实现assertListEqual()assertTupleEqual()

3.1 版中的新功能。

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

测试两个列表或元组是否相等。 如果不是,则会构建一条错误消息,仅显示两者之间的差异。 如果任一参数的类型错误,也会引发错误。 在将列表或元组与 assertEqual() 进行比较时,默认使用这些方法。

3.1 版中的新功能。

assertSetEqual(first, second, msg=None)

测试两组是否相等。 如果不是,则构建一个错误消息,列出集合之间的差异。 在将集合或冻结集与 assertEqual() 进行比较时,默认使用此方法。

如果 firstsecond 没有 set.difference() 方法,则失败。

3.1 版中的新功能。

assertDictEqual(first, second, msg=None)

测试两个字典是否相等。 如果不是,则会构造一条错误消息,显示字典中的差异。 默认情况下,此方法将用于在调用 assertEqual() 时比较字典。

3.1 版中的新功能。

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

fail(msg=None)

无条件发出测试失败信号,错误消息为 msgNone

failureException

这个类属性给出了测试方法引发的异常。 如果测试框架需要使用专门的异常,可能携带额外的信息,它必须子类化这个异常,以便与框架“公平竞争”。 该属性的初始值为 AssertionError

longMessage

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

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

在每次测试调用之前重置类设置。

3.1 版中的新功能。

maxDiff

此属性通过报告失败差异的断言方法控制差异输出的最大长度。 默认为 80*8 个字符。 受此属性影响的断言方法是 assertSequenceEqual()(包括所有委托给它的序列比较方法)、assertDictEqual()assertMultiLineEqual()

maxDiff 设置为 None 意味着没有最大差异长度。

3.2 版中的新功能。

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

countTestCases()

返回此测试对象表示的测试数量。 对于 TestCase 实例,这将始终是 1

defaultTestResult()

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

对于 TestCase 实例,这将始终是 TestResult 的实例; TestCase 的子类应该根据需要覆盖它。

id()

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

shortDescription()

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

3.1 版更改: 在 3.1 中,即使存在文档字符串,也已更改为将测试名称添加到简短描述中。 这导致了 unittest 扩展的兼容性问题,并且添加测试名称已移至 Python 3.2 中的 TextTestResult

addCleanup(function, *args, **kwargs)

tearDown()后添加一个函数,用于清理测试时使用的资源。 函数的调用顺序与它们添加的顺序相反 (LIFO)。 当它们被添加时,任何参数和关键字参数都会被调用到 addCleanup() 中。

如果 setUp() 失败,意味着 tearDown() 没有被调用,那么任何添加的清理函数仍然会被调用。

3.1 版中的新功能。

doCleanups()

如果 setUp() 引发异常,则在 tearDown()setUp() 之后无条件调用此方法。

它负责调用addCleanup()添加的所有清理函数。 如果您需要调用清理函数 priortearDown() 那么您可以自己调用 doCleanups()

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

3.1 版中的新功能。

class unittest.FunctionTestCase(testFunc, setUp=None, tearDown=None, description=None)
此类实现了 TestCase 接口的一部分,该接口允许测试运行器驱动测试,但不提供测试代码可用于检查和报告错误的方法。 这用于使用遗留测试代码创建测试用例,允许将其集成到基于 unittest 的测试框架中。

不推荐使用的别名

由于历史原因,某些 TestCase 方法具有一个或多个现已弃用的别名。 下表列出了正确的名称及其已弃用的别名:

方法名称 不推荐使用的别名 不推荐使用的别名
assertEqual() 失败除非相等 断言等于
assertNotEqual() 失败如果相等 断言不等于
assertTrue() 除非失败 断言_
assertFalse() 如果失败
assertRaises() 失败除非加注
assertAlmostEqual() 失败除非几乎相等 断言几乎等于
assertNotAlmostEqual() 失败如果几乎相等 assertNotAlmostEquals
assertRegex() 断言正则表达式匹配
assertNotRegex() assertNotRegexpMatches
assertRaisesRegex() assertRaisesRegexp

自 3.1 版起已弃用:第二列中列出的失败* 别名已被弃用。


自 3.2 版起已弃用:第三列中列出的 assert* 别名已被弃用。


自 3.2 版起已弃用:assertRegexpMatchesassertRaisesRegexp 已重命名为 assertRegex()assertRaisesRegex()


自 3.5 版起已弃用: assertNotRegexpMatches 名称已弃用,取而代之的是 assertNotRegex()


分组测试

class unittest.TestSuite(tests=())

此类表示单个测试用例和测试套件的聚合。 该类提供了测试运行器所需的接口,以允许它像任何其他测试用例一样运行。 运行 TestSuite 实例与迭代套件相同,单独运行每个测试。

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

TestSuite 对象的行为与 TestCase 对象非常相似,但它们实际上并不实现测试。 相反,它们用于将测试聚合成应该一起运行的测试组。 一些额外的方法可用于向 TestSuite 实例添加测试:

addTest(test)

向套件添加 TestCaseTestSuite

addTests(tests)

将来自 TestCaseTestSuite 实例的迭代中的所有测试添加到此测试套件中。

这相当于迭代 tests,为每个元素调用 addTest()

TestSuiteTestCase 共享以下方法:

run(result)

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

debug()

运行与此套件关联的测试而不收集结果。 这允许将测试引发的异常传播给调用者,并可用于支持在调试器下运行测试。

countTestCases()

返回此测试对象表示的测试数量,包括所有单独的测试和子套件。

__iter__()

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

3.2 版更改: 在早期版本中,TestSuite 直接访问测试而不是通过迭代,因此覆盖 __iter__() 不足以提供测试。

在 3.4 版中更改: 在早期版本中,TestSuiteTestSuite.run() 之后持有对每个 TestCase 的引用。 子类可以通过覆盖 TestSuite._removeTestAtIndex() 来恢复该行为。

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


加载和运行测试

class unittest.TestLoader

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

TestLoader 对象具有以下属性:

errors

加载测试时遇到的非致命错误的列表。 加载器在任何时候都不会重置。 致命错误由相关的 a 方法发出信号,该方法向调用者引发异常。 非致命错误也由综合测试指示,该测试将在运行时引发原始错误。

3.5 版中的新功能。

TestLoader 对象有以下方法:

loadTestsFromTestCase(testCaseClass)

返回包含在 TestCase 派生的 testCaseClass 中的所有测试用例的套件。

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

loadTestsFromModule(module, pattern=None)

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

笔记

虽然使用 TestCase 派生类的层次结构可以方便地共享夹具和辅助函数,但在不打算直接实例化的基类上定义测试方法并不适合这种方法。 但是,当设备不同并在子类中定义时,这样做会很有用。

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

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

3.5 版更改: 未记录和非官方的 use_load_tests 默认参数已弃用并被忽略,尽管它仍被接受以实现向后兼容性。 该方法现在还接受一个仅关键字参数 pattern,该参数作为第三个参数传递给 load_tests

loadTestsFromName(name, module=None)

返回一组给定字符串说明符的所有测试用例。

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

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

该方法可选地解析 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)

通过从指定的起始目录递归到子目录中查找所有测试模块,并返回包含它们的 TestSuite 对象。 只会加载匹配 模式 的测试文件。 (使用 shell 样式模式匹配。)只有可导入的模块名称(即 是有效的 Python 标识符)将被加载。

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

如果导入模块失败,例如由于语法错误,那么这将被记录为单个错误并且发现将继续。 如果导入失败是由于 SkipTest 被引发,它会被记录为跳过而不是错误。

如果找到包(包含名为 __init__.py 的文件的目录),将检查该包的 load_tests 函数。 如果存在,那么它将被称为 package.load_tests(loader, tests, pattern)。 即使 load_tests 函数本身调用 loader.discover,测试发现也会确保在调用期间只检查一次包的测试。

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

该模式故意不存储为加载程序属性,以便包可以继续自行发现。 top_level_dir 已存储,因此 load_tests 不需要将此参数传递给 loader.discover()

start_dir 可以是带点的模块名称也可以是目录。

3.2 版中的新功能。

在 3.4 版中更改:在导入时引发 SkipTest 的模块被记录为跳过,而不是错误。 发现适用于 命名空间包 。 路径在导入之前进行排序,因此即使底层文件系统的排序不依赖于文件名,执行顺序也是相同的。

在 3.5 版更改:现在检查找到的包是否有 load_tests,无论它们的路径是否匹配 pattern,因为包名不可能与默认模式匹配.

TestLoader 的以下属性可以通过实例的子类化或赋值来配置:

testMethodPrefix

给出将被解释为测试方法的方法名称前缀的字符串。 默认值为 'test'

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

sortTestMethodsUsing

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

suiteClass

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

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

testNamePatterns

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

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

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

3.7 版中的新功能。

class unittest.TestResult

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

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

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

TestResult 实例具有以下属性,这些属性在检查运行一组测试的结果时会很重要:

errors

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

failures

包含 TestCase 实例的 2 元组和保存格式化回溯的字符串的列表。 每个元组代表一个测试,其中使用 TestCase.assert*() 方法明确发出故障信号。

skipped

包含 TestCase 实例的 2 元组和包含跳过测试原因的字符串的列表。

3.1 版中的新功能。

expectedFailures

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

unexpectedSuccesses

包含标记为预期失败但成功的 TestCase 实例的列表。

shouldStop

当测试的执行应该通过 stop() 停止时,设置为 True

testsRun

到目前为止运行的测试总数。

buffer

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

3.2 版中的新功能。

failfast

如果设置为 true stop() 将在第一次失败或错误时调用,停止测试运行。

3.2 版中的新功能。

tb_locals

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

3.5 版中的新功能。

wasSuccessful()

如果到目前为止运行的所有测试都通过,则返回 True,否则返回 False

在 3.4 版中更改: 如果来自用 expectedFailure() 装饰器标记的测试中有任何 unexpectedSuccesses,则返回 False

stop()

可以通过将 shouldStop 属性设置为 True 来调用此方法,以表示应中止正在运行的测试集。 TestRunner 对象应该尊重这个标志并返回而不运行任何额外的测试。

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

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

startTest(test)

当测试用例 test 即将运行时调用。

stopTest(test)

在测试用例 test 执行后调用,无论结果如何。

startTestRun()

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

3.1 版中的新功能。

stopTestRun()

在所有测试执行后调用一次。

3.1 版中的新功能。

addError(test, err)

当测试用例 test 引发意外异常时调用。 errsys.exc_info(): (type, value, traceback) 返回的形式的元组。

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

addFailure(test, err)

当测试用例 test 发出失败信号时调用。 errsys.exc_info(): (type, value, traceback) 返回的形式的元组。

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

addSuccess(test)

当测试用例 test 成功时调用。

默认实现什么都不做。

addSkip(test, reason)

在跳过测试用例 test 时调用。 reason 是测试给出跳过的原因。

默认实现将元组 (test, reason) 附加到实例的 跳过 属性。

addExpectedFailure(test, err)

当测试用例 test 失败时调用,但被标记为 expectedFailure() 装饰器。

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

addUnexpectedSuccess(test)

当测试用例 test 被标记为 expectedFailure() 装饰器时调用,但成功了。

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

addSubTest(test, subtest, outcome)

当子测试完成时调用。 test是测试方法对应的测试用例。 subtest 是描述子测试的自定义 TestCase 实例。

如果 outcomeNone,则子测试成功。 否则,它会失败并出现异常,其中 outcomesys.exc_info(): (type, value, traceback) 返回的形式的元组。

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

3.4 版中的新功能。

class unittest.TextTestResult(stream, descriptions, verbosity)

TextTestRunner 使用的 TestResult 的具体实现。

3.2 新功能: 这个类以前被命名为 _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)

将结果输出到流的基本测试运行器实现。 如果streamNone,则默认使用sys.stderr作为输出流。 这个类有一些可配置的参数,但本质上非常简单。 运行测试套件的图形应用程序应该提供替代实现。 此类实现应接受 **kwargs 作为在将功能添加到单元测试时构造运行程序更改的接口。

默认情况下,此运行程序显示 DeprecationWarningPendingDeprecationWarningResourceWarningImportWarning,即使它们在默认情况下被 X185X忽略。 由 已弃用的单元测试方法 引起的弃用警告也是特殊情况,当警告过滤器为 '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(test)

该方法是TextTestRunner的主要公共接口。 此方法采用 TestSuiteTestCase 实例。 TestResult 是通过调用 _makeResult() 创建的,然后运行测试并将结果打印到标准输出。

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

一个命令行程序,从 module 加载一组测试并运行它们; 这主要是为了使测试模块可以方便地执行。 此函数最简单的用法是在测试脚本的末尾包含以下行:

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

您可以通过传入 verbosity 参数来运行具有更详细信息的测试:

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

如果没有通过 argv 指定测试名称,则 defaultTest 参数是单个测试的名称或要运行的可迭代测试名称。 如果未指定或 None 且未通过 argv 提供测试名称,则运行 模块 中的所有测试。

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

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

testLoader 参数必须是一个 TestLoader 实例,并且默认为 defaultTestLoader

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

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

failfastcatchbreakbuffer 参数与同名 命令行选项 具有相同的效果。

warnings 参数指定在运行测试时应该使用的 warning 过滤器 。 如果未指定,如果将-W选项传递给python,则保持None(见警告控制),否则将被设置'default'

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

3.1 版更改: 添加了 出口 参数。

在 3.2 版更改:详细failfastcatchbreakbuffer和29X警告[X] ] 参数已添加。

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

load_tests 协议

3.2 版中的新功能。


通过实现一个名为 load_tests 的函数,模块或包可以自定义在正常测试运行或测试发现期间如何从它们加载测试。

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

load_tests(loader, standard_tests, pattern)

其中 patternloadTestsFromModule 直接通过。 默认为 None

它应该返回一个 TestSuite

loader 是执行加载的 TestLoader 的实例。 standard_tests 是默认情况下从模块加载的测试。 测试模块通常只想在标准测试集中添加或删除测试。 第三个参数在加载包作为测试发现的一部分时使用。

从一组特定的 TestCase 类加载测试的典型 load_tests 函数可能如下所示:

test_cases = (TestCase1, TestCase2, TestCase3)

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

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

load_tests(loader, standard_tests, pattern)

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

因为模式被传递到 load_tests 包可以自由地继续(并可能修改)测试发现。 测试包的“什么都不做”load_tests 函数如下所示:

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

在 3.5 版更改: 由于包名称不可能与默认模式匹配,因此发现不再检查包名称是否匹配 模式


类和模块夹具

类和模块级装置在 TestSuite 中实现。 当测试套件遇到来自新类的测试时,则调用来自前一个类(如果有)的 tearDownClass(),然后是来自新类的 setUpClass()

类似地,如果测试来自与先前测试不同的模块,则运行来自先前模块的 tearDownModule,然后是来自新模块的 setUpModule

在所有测试运行后,运行最终的 tearDownClasstearDownModule

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

unittest 测试加载器创建的测试的默认顺序是将来自相同模块和类的所有测试组合在一起。 这将导致 setUpClass / setUpModule(等)每个类和模块只被调用一次。 如果您将顺序随机化,使得来自不同模块和类的测试彼此相邻,那么这些共享的夹具函数可能会在单个测试运行中被多次调用。

共享装置不适用于非标准订购的套件。 对于不想支持共享设备的框架,BaseTestSuite 仍然存在。

如果在共享夹具功能之一期间出现任何异常,则将测试报告为错误。 因为没有相应的测试实例,所以会创建一个 _ErrorHolder 对象(与 TestCase 具有相同的接口)来表示错误。 如果您只是使用标准的 unittest 测试运行器,那么这个细节并不重要,但如果您是框架作者,它可能是相关的。

setUpClass 和 tearDownClass

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

import unittest

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

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

如果您想要调用基类上的 setUpClasstearDownClass,那么您必须自己调用它们。 TestCase 中的实现是空的。

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


setUpModule 和 tearDownModule

这些应该作为函数来实现:

def setUpModule():
    createConnection()

def tearDownModule():
    closeConnection()

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


信号处理

3.2 版中的新功能。


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

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

框架作者有一些实用函数可以在测试框架中启用 control-c 处理功能。

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

注册一个 TestResult 对象用于 control-c 处理。 注册结果会存储对它的弱引用,因此它不会阻止结果被垃圾收集。

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

unittest.removeResult(result)
删除已注册的结果。 一旦结果被删除,那么 stop() 将不再在该结果对象上调用以响应 control-c。
unittest.removeHandler(function=None)

如果不带参数调用此函数,则会删除已安装的 control-c 处理程序。 此函数还可用作测试装饰器,以在执行测试时临时删除处理程序:

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