Skip to main content

26.4. unittest —单元测试框架

源代码: Lib/unittest/__init__.py


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

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

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

测试夹具

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

测试用例

test case 是测试的单独单元。它检查对特定输入集合的特定响应。 unittest 提供了一个基类 TestCase,可用于创建新的测试用例。

测试套件

test suite 是测试用例,测试套件或两者的集合。它用于聚合应该一起执行的测试。

测试跑步者

test runner 是协调测试执行并向用户提供结果的组件。运行器可以使用图形界面,文本界面,或返回特定值来指示执行测试的结果。

参见

模块 doctest

另一个具有非常不同风味的测试支持模块。

简单Smalltalk测试:与模式

Kent Beck关于使用 unittest 共享模式的测试框架的原始文章。

鼻子py.test

第三方单元测试框架具有用于书写测试的更轻量级语法。例如,assert func(10) == 42

Python测试工具分类法

广泛的Python测试工具列表,包括功能测试框架和模拟对象库。

在Python邮件列表中测试

在Python中讨论测试和测试工具的特殊兴趣小组。

Python源代码分发中的脚本 Tools/unittestgui/unittestgui.py 是用于测试发现和执行的GUI工具。这主要是为了易于使用那些新的单元测试。对于生产环境,建议由连续集成系统(如 Buildbot詹金斯哈德森)驱动测试。

26.4.1. 基本示例

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 功能,足以满足许多日常测试需求。本文档的其余部分探讨了第一个原则的完整功能集。

26.4.2. 命令行界面

unittest模块可以从命令行使用,从模块,类或单独的测试方法运行测试:

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

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

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

python -m unittest tests/test_something.py

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

您可以通过传递-v标志来运行具有更多细节(更高冗余)的测试:

python -m unittest -v test_module

当执行无参数 测试发现 时启动:

python -m unittest

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

python -m unittest -h

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

26.4.2.1. 命令行选项

unittest 支持以下命令行选项:

-b, --buffer

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

-c, --catch

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

有关提供此功能的函数,请参阅 Signal Handling

-f, --failfast

在第一个错误或故障时停止测试运行。

--locals

在traceback中显示局部变量。

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

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

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

26.4.3. 测试发现

3.2 新版功能.

Unittest支持简单的测试发现。为了与测试发现兼容,所有测试文件必须是可从项目的顶级目录导入的 模块 (包括 命名空间包)(这意味着它们的文件名必须是有效的 身份标识)。

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

cd project_directory
python -m unittest discover

注解

作为一个捷径,python -m unittest 相当于 python -m unittest discover。如果要传递参数以进行测试发现,则必须显式地使用 discover 子命令。

discover 子命令有以下选项:

-v, --verbose

详细输出

-s, --start-directory directory

开始发现的目录(. 默认)

-p, --pattern pattern

匹配测试文件的模式(test*.py 默认)

-t, --top-level-directory directory

项目顶层目录(默认为开始目录)

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

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

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

警告

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

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

如果您提供开始目录作为包名称而不是目录的路径,则发现假定它从其导入的任何位置是您想要的位置,因此您不会得到警告。

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

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

26.4.4. 组织测试代码

单元测试的基本构建块是 test cases —必须设置和检查正确性的单个场景。在 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。任何其他异常将被视为 errors

测试可以是众多的,并且它们的设置可以是重复的。幸运的是,我们可以通过实现一个称为 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() 将运行测试方法是否成功。

这种测试代码的工作环境称为 fixture

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

但是,如果您想要定制测试套件的构建,您可以自己做:

def suite():
    suite = unittest.TestSuite()
    suite.addTest(WidgetTestCase('test_default_size'))
    suite.addTest(WidgetTestCase('test_resize'))
    return suite

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

  • 测试模块可以从命令行独立运行。

  • 测试代码可以更容易地与运输代码分开。

  • 有更少的诱惑改变测试代码,以适应代码测试没有一个很好的理由。

  • 测试代码的修改频率要比它测试的代码少得多。

  • 测试代码可以更容易重构。

  • 用C编写的模块的测试必须在单独的模块中,所以为什么不一致?

  • 如果测试策略更改,则不需要更改源代码。

26.4.5. 重新使用旧的测试代码

一些用户会发现他们有现成的测试代码,他们想从 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 实例。

26.4.6. 跳过测试和预期失败

3.1 新版功能.

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

跳过测试只是使用 skip() decorator 或其条件变体之一。

基本跳过看起来像这样:

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

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

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

----------------------------------------------------------------------
Ran 3 tests in 0.005s

OK (skipped=3)

类可以像方法一样跳过:

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

26.4.7. 使用分测验来区分测试迭代

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

26.4.8. 类和函数

本节深入描述 unittest 的API。

26.4.8.1. 测试用例

class unittest.TestCase(methodName='runTest')

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

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

在 3.2 版更改: TestCase 可以成功实例化,而不提供 methodName。这使得从交互式解释器更容易实验 TestCase

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

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

setUp()

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

tearDown()

方法调用后立即调用测试方法并记录结果。即使测试方法引发了异常,也会调用此方法,因此子类中的实现可能需要特别注意检查内部状态。由这种方法引起的任何异常,除了 AssertionErrorSkipTest,将被认为是附加错误,而不是测试失败(因此增加报告的错误的总数)。仅当 setUp() 成功时才调用此方法,而不管测试方法的结果如何。默认实现什么也不做。

setUpClass()

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

@classmethod
def setUpClass(cls):
    ...

有关详细信息,请参阅 Class and Module Fixtures

3.2 新版功能.

tearDownClass()

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

@classmethod
def tearDownClass(cls):
    ...

有关详细信息,请参阅 Class and Module Fixtures

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

所有的assert方法都接受一个 msg 参数,如果指定了该参数,那么它将作为失败时的错误消息使用(参见 longMessage)。注意,只有当它们用作上下文管理器时,msg 关键字参数才能被传递到 assertRaises()assertRaisesRegex()assertWarns()assertWarnsRegex()

assertEqual(first, second, msg=None)

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

此外,如果 firstsecond 是完全相同的类型以及list,tuple,dict,set,frozenset或str或子类向 addTypeEqualityFunc() 注册的任何类型中的一个,则将调用类型特定的等式函数,以便生成更多有用的默认错误消息(另见 类型特定方法的列表)。

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

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

assertNotEqual(first, second, msg=None)

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

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

测试 expr 是真(或假)。

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

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

测试 firstsecond 评估(或不评估)同一个对象。

3.1 新版功能.

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

测试 expr 是(或不是) None

3.1 新版功能.

assertIn(first, second, msg=None)
assertNotIn(first, second, msg=None)

测试 first 是(或不是) second

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 块以最小的 level 登录 logger

3.4

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

测试当使用也传递给 assertRaises() 的任何位置或关键字参数调用 callable 时引发异常。如果 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)

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

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

with self.assertWarns(SomeWarning):
    do_something()

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

上下文管理器将捕获的警告对象存储在其 warning 属性中,以及触发 filenamelineno 属性中的警告的源行。如果意图是对捕获的警告执行附加检查,这可能是有用的:

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

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

此方法工作时,无论警告过滤器在适当的地方,当它被调用。

3.2 新版功能.

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

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

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

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

要么:

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

3.2 新版功能.

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

assertLogs(logger=None, level=None)

上下文管理器测试至少一个消息被记录在 logger 或它的一个孩子上,至少具有给定的 level

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

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

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

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

records

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

output

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

例:

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

3.4 新版功能.

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

方法

检查

新的

assertAlmostEqual(a, b)

round(a-b, 7) == 0

 

assertNotAlmostEqual(a, b)

round(a-b, 7) != 0

 

assertGreater(a, b)

a > b

3.1

assertGreaterEqual(a, b)

a >= b

3.1

assertLess(a, b)

a < b

3.1

assertLessEqual(a, b)

a <= b

3.1

assertRegex(s, r)

r.search(s)

3.1

assertNotRegex(s, r)

not r.search(s)

3.2

assertCountEqual(a, b)

ab 具有相同数量的相同元素,而不管它们的顺序如何

3.2

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

通过计算差值,四舍五入到给定的十进制 places 数(默认值7),并与零比较,测试 firstsecond 是否近似(或不近似)相等。注意,这些方法将值舍入到给定数目的 小数位 (即,类似于 round() 函数)而不是 有效数字

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

供应 deltaplaces 产生 TypeError

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

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

根据方法名称,测试 first 分别为>,> =,<或<=比 second。如果没有,测试将失败:

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

3.1 新版功能.

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

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

3.1 新版功能: 以名称 assertRegexpMatches

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

3.2 新版功能: assertNotRegex()

assertCountEqual(first, second, msg=None)

测试序列 first 包含与 second 相同的元素,而不考虑它们的顺序。当它们没有时,将产生列出序列之间的差异的错误消息。

当比较 firstsecond 时,重复的元素被 not 忽略。它验证每个元素在两个序列中是否具有相同的计数。等效于: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)

集或frozensets

3.1

assertDictEqual(a, b)

dicts

3.1

assertMultiLineEqual(first, second, msg=None)

测试多行字符串 first 等于字符串 second。当不相等时,高亮显示差异的两个字符串的diff将包含在错误消息中。在将字符串与 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

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

maxDiff 设置为 None 意味着没有diff的最大长度。

3.2 新版功能.

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

countTestCases()

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

defaultTestResult()

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

对于 TestCase 实例,这将始终是 TestResult 的实例; TestCase 的子类应该在必要时重写此。

id()

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

shortDescription()

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

在 3.1 版更改: 在3.1中,这被更改为将测试名称添加到简短描述,即使在docstring的存在。这导致与单元测试扩展的兼容性问题,并将测试名称移动到Python 3.2中的 TextTestResult

addCleanup(function, *args, **kwargs)

添加要在 tearDown() 后调用的函数,以清除测试期间使用的资源。函数将按照它们添加的顺序(LIFO(后进先出))以相反的顺序调用。当它们被添加时,它们被传递到 addCleanup() 中的任何参数和关键字参数被调用。

如果 setUp() 失败,意味着 tearDown() 不被调用,则添加的任何清除函数仍将被调用。

3.1 新版功能.

doCleanups()

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

它负责调用由 addCleanup() 添加的所有清除功能。如果你需要清理功能被称为 priortearDown(),那么你可以自己调用 doCleanups()

doCleanups() 一次一个地从一堆清除函数中抛出方法,因此可以随时调用它。

3.1 新版功能.

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

这个类实现了 TestCase 接口的一部分,它允许测试运行器驱动测试,但不提供测试代码可以用来检查和报告错误的方法。这用于使用旧测试代码创建测试用例,允许将其集成到基于 unittest 的测试框架中。

26.4.8.1.1. 已弃用的别名

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

方法名称

已弃用的别名

已弃用的别名

assertEqual()

failUnlessEqual

assertEquals

assertNotEqual()

failIfEqual

assertNotEquals

assertTrue()

failUnless

断言_

assertFalse()

失败

 

assertRaises()

failUnlessRaises

 

assertAlmostEqual()

failUnlessAlmostEqual

assertAlmostEquals

assertNotAlmostEqual()

failIfAlmostEqual

assertNotAlmostEquals

assertRegex()

 

assertRegexpMatches

assertRaisesRegex()

 

assertRaisesRegexp

3.1 版后已移除: 第二列中列出的失败*别名。

3.2 版后已移除: 在第三列中列出的 assert* 别名。

3.2 版后已移除: assertRegexpMatchesassertRaisesRegexp 已更名为 assertRegex()assertRaisesRegex()

26.4.8.2. 分组测试

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 版更改: 在早期版本中,TestSuite 持有对 TestSuite.run() 之后的每个 TestCase 的引用。子类可以通过重写 TestSuite._removeTestAtIndex() 来恢复该行为。

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

26.4.8.3. 加载和运行测试

class unittest.TestLoader

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

TestLoader 对象具有以下属性:

errors

加载测试时遇到的非致命错误的列表。不由装载器在任何点复位。致命错误由相关的调用者引发异常的方法指示。非致命错误也由合成测试指示,这将在运行时提高原始错误。

3.5 新版功能.

TestLoader 对象有以下方法:

loadTestsFromTestCase(testCaseClass)

返回一组包含在 TestCase - 来自 testCaseClass 中的所有测试用例。

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

loadTestsFromModule(module, pattern=None)

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

注解

虽然使用 TestCase -derived类的层次结构可以方便地共享fixture和辅助函数,但是基本类上定义测试方法不能直接实例化并不适用于此方法。但是,当夹具不同并且在子类中定义时,这样做是有用的。

如果模块提供 load_tests 功能,它将被调用来加载测试。这允许模块自定义测试加载。这是 load_tests protocolpattern 参数作为第三个参数传递给 load_tests

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

在 3.5 版更改: 无记录和非正式的 use_load_tests 默认参数被弃用和忽略,虽然它仍然被接受为向后兼容性。该方法现在还接受一个只传递给 load_tests 的参数 pattern 作为第三个参数。

loadTestsFromName(name, module=None)

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

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

例如,如果您有一个模块 SampleTests 包含一个 TestCase 派生的具有三种测试方法(test_one()test_two()test_three())的 SampleTestCase 类,则说明符 '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)

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

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

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

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

如果 load_tests 存在,则发现 not 递归到包中,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*() 方法。

class unittest.TestResult

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

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

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

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

errors

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

failures

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

skipped

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

3.1 新版功能.

expectedFailures

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

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,那么局部变量将显示在traceback中。

3.5 新版功能.

wasSuccessful()

如果所有运行的测试都已通过,则返回 True,否则返回 False

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

stop()

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

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

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

startTest(test)

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

stopTest(test)

在测试用例 test 被执行后调用,不管结果如何。

startTestRun()

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

3.1 新版功能.

stopTestRun()

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

3.1 新版功能.

addError(test, err)

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

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

addFailure(test, err)

当测试用例 test 发出故障信号时调用。 err 是由 sys.exc_info()(type, value, traceback) 返回的形式的元组。

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

addSuccess(test)

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

默认实现什么也不做。

addSkip(test, reason)

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

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

addExpectedFailure(test, err)

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

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

addUnexpectedSuccess(test)

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

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

addSubTest(test, subtest, outcome)

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

如果 outcomeNone,则子测试成功。否则,它失败了一个异常,其中 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 作为接口,以便在将特征添加到unittest时构造runners变化。

默认情况下,这个转轮显示 DeprecationWarningPendingDeprecationWarningResourceWarningImportWarning,即使它们是 默认情况下忽略。由 不推荐的单位测试方法 引起的弃用警告也是特殊的,当警告过滤器为 'default''always' 时,它们每个模块只出现一次,以避免过多的警告消息。可以使用Python的 -Wd-Wa 选项(请参阅 警告控制)覆盖此行为,并将 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 实例。通过调用 _makeResult() 创建 TestResult,并运行测试并将结果打印到stdout。

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

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

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

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

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

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

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

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

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

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

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

failfastcatchbreakbuffer 参数具有与同名 command-line options 相同的效果。

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

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

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

在 3.2 版更改: 加入 verbosityfailfastcatchbreakbufferwarnings 参数。

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

26.4.8.3.1. load_tests协议

3.2 新版功能.

模块或包可以通过实现称为 load_tests 的函数来定制在正常测试运行或测试发现期间从它们加载测试的方式。

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

load_tests(loader, standard_tests, pattern)

其中 patternloadTestsFromModule 直接传递。它默认为 None

它应该返回一个 TestSuite

loaderTestLoader 执行加载的实例。 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__.pyload_tests。如果该函数不存在,发现将递归到包中,就好像它只是另一个目录。否则,发现程序包的测试将留给 load_tests,它使用以下参数调用:

load_tests(loader, standard_tests, pattern)

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

因为模式被传递到 load_tests,所以包可以自由地继续(并潜在地修改)测试发现。 A’do nothing’测试包的 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,因为包名称不匹配默认模式。

26.4.9. 类和模块夹具

类和模块级夹具在 TestSuite 中实现。当测试套件遇到来自新类的测试时,则调用来自上一个类的 tearDownClass() (如果有一个),接着是来自新类的 setUpClass()

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

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

注意,共享夹具不能很好地与测试并行化的潜在特性一起工作,并且它们会破坏测试隔离。他们应该小心使用。

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

共享灯具不适用于非标准订购的套房。 BaseTestSuite 仍然存在于不想支持共享夹具的框架。

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

26.4.9.1. 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 异常,那么类将被报告为已跳过,而不是作为错误。

26.4.9.2. setUpModule和tearDownModule

这些应该作为函数实现:

def setUpModule():
    createConnection()

def tearDownModule():
    closeConnection()

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

26.4.10. 信号处理

3.2 新版功能.

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

控制c处理信号处理程序试图保持与安装自己的 signal.SIGINT 处理程序的代码或测试兼容。如果 unittest 处理程序被调用,但是 isn’t 已安装的 signal.SIGINT 处理程序,即它已被被测系统取代并委托给它,则它调用默认处理程序。这通常是通过代码替换已安装的处理程序并委派给它的预期行为。对于需要 unittest 控制-c处理的单独测试,可以使用 removeHandler() 装饰器。

框架作者有几个实用函数用于在测试框架内启用控制c处理功能。

unittest.installHandler()

安装control-c处理程序。当接收到 signal.SIGINT 时(通常响应于用户按压控制c)所有注册的结果都被 stop() 调用。

unittest.registerResult(result)

注册 TestResult 对象以进行控制c处理。注册结果存储了一个弱引用,因此它不会阻止结果被垃圾回收。

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

unittest.removeResult(result)

删除已注册的结果。一旦结果被移除,则 stop() 将不再响应于控制c而在该结果对象上被调用。

unittest.removeHandler(function=None)

当调用无参数时,如果已安装control-c处理程序,则此函数将删除它。此函数也可以用作测试装饰器,以便在执行测试时临时删除处理程序:

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