unittest
— 单元测试框架¶
(如果您已经熟悉测试的基本概念,您可能想跳到断言方法列表。)
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 工具。这主要是为了方便那些刚接触单元测试的人使用。对于生产环境,建议测试由持续集成系统驱动,例如 Buildbot、Jenkins、GitHub Actions 或 AppVeyor。
基本示例¶
unittest
模块提供了一组丰富的工具来构建和运行测试。本节演示了一小部分工具足以满足大多数用户的需求。
这是一个测试三个字符串方法的简短脚本
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
通过子类化 unittest.TestCase
来创建测试用例。三个单独的测试由名称以字母 test
开头的方法定义。此命名约定会告知测试运行器哪些方法表示测试。
每个测试的关键是对 assertEqual()
的调用,以检查预期结果; assertTrue()
或 assertFalse()
来验证条件;或 assertRaises()
来验证是否引发了特定异常。这些方法代替了 assert
语句,以便测试运行器可以累积所有测试结果并生成报告。
setUp()
和 tearDown()
方法允许您定义将在每个测试方法之前和之后执行的指令。它们在组织测试代码部分进行了更详细的介绍。
最后一块显示了运行测试的简单方法。unittest.main()
为测试脚本提供了命令行界面。从命令行运行时,上面的脚本会生成如下所示的输出
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
将 -v
选项传递给您的测试脚本将指示 unittest.main()
启用更高级别的详细程度,并产生以下输出
test_isupper (__main__.TestStringMethods.test_isupper) ... ok
test_split (__main__.TestStringMethods.test_split) ... ok
test_upper (__main__.TestStringMethods.test_upper) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
上面的示例显示了最常用的 unittest
功能,这些功能足以满足许多日常测试需求。其余文档从第一原理探讨了完整的功能集。
在 3.11 版本中变更: 现在不推荐从测试方法返回一个值(除了默认的 None
值)。
命令行接口¶
可以从命令行使用 unittest 模块来运行模块、类甚至单个测试方法中的测试。
python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
您可以传入一个列表,其中包含模块名称、完全限定的类名或方法名的任意组合。
也可以通过文件路径指定测试模块。
python -m unittest tests/test_something.py
这允许您使用 shell 文件名补全来指定测试模块。指定的文件仍然必须可以作为模块导入。通过删除“.py”并将路径分隔符转换为“.”,将路径转换为模块名称。如果要执行一个不能作为模块导入的测试文件,您应该直接执行该文件。
您可以通过传入 -v 标志来运行更详细(更高详细程度)的测试。
python -m unittest -v test_module
在不带参数执行时,将启动测试发现。
python -m unittest
有关所有命令行选项的列表
python -m unittest -h
在 3.2 版本中变更: 在早期版本中,只能运行单个测试方法,而不能运行模块或类。
命令行选项¶
unittest 支持以下命令行选项
- -b, --buffer¶
在测试运行期间,标准输出和标准错误流会被缓冲。在通过测试期间的输出会被丢弃。在测试失败或错误时,输出会正常回显,并添加到失败消息中。
- -c, --catch¶
在测试运行期间按下 Control-C 会等待当前测试结束,然后报告到目前为止的所有结果。第二次按下 Control-C 会引发正常的
KeyboardInterrupt
异常。有关提供此功能的函数,请参阅 信号处理。
- -f, --failfast¶
在第一次出现错误或失败时停止测试运行。
- -k¶
仅运行与模式或子字符串匹配的测试方法和类。此选项可以多次使用,在这种情况下,将包含与任何给定模式匹配的所有测试用例。
包含通配符 (
*
) 的模式将使用fnmatch.fnmatchcase()
与测试名称进行匹配;否则,将使用简单的区分大小写的子字符串匹配。模式将与测试加载器导入的完全限定的测试方法名称进行匹配。
例如,
-k foo
将匹配foo_tests.SomeTest.test_something
、bar_tests.SomeTest.test_foo
,但不匹配bar_tests.FooTest.test_something
。
- --locals¶
在回溯中显示局部变量。
- --durations N¶
显示 N 个最慢的测试用例(N=0 表示全部)。
在 3.2 版本中新增: 添加了命令行选项 -b
、-c
和 -f
。
在 3.5 版本中新增: 添加了命令行选项 --locals
。
在 3.7 版本中新增: 添加了命令行选项 -k
。
在 3.12 版本中新增: 添加了命令行选项 --durations
。
命令行还可以用于测试发现,用于运行项目中的所有测试或仅运行一部分测试。
测试发现¶
在 3.2 版本中新增。
Unittest 支持简单的测试发现。为了与测试发现兼容,所有测试文件都必须是可以从项目的顶层目录导入的模块或包(这意味着它们的文件名必须是有效的标识符)。
测试发现是在 TestLoader.discover()
中实现的,但也可以从命令行使用。基本的命令行用法是
cd project_directory
python -m unittest discover
注解
作为快捷方式,python -m unittest
等同于 python -m unittest discover
。如果您想将参数传递给测试发现,则必须显式使用 discover
子命令。
discover
子命令具有以下选项
- -v, --verbose¶
详细输出
- -s, --start-directory directory¶
启动发现的目录(默认值为
.
)
- -p, --pattern pattern¶
匹配测试文件的模式(默认值为
test*.py
)
- -t, --top-level-directory directory¶
项目的顶层目录(默认为起始目录)
可以将 -s
、-p
和 -t
选项按该顺序作为位置参数传入。以下两个命令行是等效的
python -m unittest discover -s project_directory -p "*_test.py"
python -m unittest discover project_directory "*_test.py"
除了作为路径之外,还可以将包名称(例如 myproject.subpackage.test
)作为起始目录传递。您提供的包名称将被导入,并且其在文件系统上的位置将用作起始目录。
注意
测试发现通过导入来加载测试。一旦测试发现从您指定的起始目录找到所有测试文件,它就会将路径转换为要导入的包名称。例如,foo/bar/baz.py
将作为 foo.bar.baz
导入。
如果您在全局安装了一个包,并尝试在包的不同副本上进行测试发现,那么导入可能会从错误的位置发生。如果发生这种情况,测试发现会警告您并退出。
如果您将起始目录作为包名称而不是目录路径提供,那么发现会假定它导入的任何位置都是您打算的位置,因此您不会收到警告。
测试模块和包可以通过 load_tests 协议自定义测试加载和发现。
在 3.4 版本中变更: 测试发现支持起始目录的命名空间包。请注意,您还需要指定顶层目录(例如 python -m unittest discover -s root/namespace -t root
)。
在 3.11 版本中变更: unittest
在 Python 3.11 中放弃了对命名空间包的支持。自 Python 3.7 以来,它一直处于损坏状态。包含测试的起始目录和子目录必须是具有 __init__.py
文件的常规包。
包含起始目录的目录仍然可以是命名空间包。在这种情况下,您需要将起始目录指定为点分隔的包名称,并显式指定目标目录。例如
# proj/ <-- current directory
# namespace/
# mypkg/
# __init__.py
# test_mypkg.py
python -m unittest discover -s namespace.mypkg -t .
组织测试代码¶
单元测试的基本构建块是测试用例 — 必须设置并检查正确性的单个场景。在 unittest
中,测试用例由 unittest.TestCase
实例表示。要创建自己的测试用例,您必须编写 TestCase
的子类,或者使用 FunctionTestCase
。
TestCase
实例的测试代码应该是完全独立的,这样它既可以单独运行,也可以与任意数量的其他测试用例组合运行。
最简单的 TestCase
子类将简单地实现一个测试方法(即名称以 test
开头的方法)以执行特定的测试代码
import unittest
class DefaultWidgetSizeTestCase(unittest.TestCase):
def test_default_widget_size(self):
widget = Widget('The widget')
self.assertEqual(widget.size(), (50, 50))
请注意,为了测试某些内容,我们使用 assert* 方法,这些方法由 TestCase
基类提供。如果测试失败,将引发带有解释性消息的异常,并且 unittest
会将测试用例标识为失败。任何其他异常都将被视为错误。
测试可能有很多,并且它们的设置可能会重复。幸运的是,我们可以通过实现一个名为 setUp()
的方法来分解设置代码,测试框架会自动为我们运行的每个测试调用该方法
import unittest
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def test_default_widget_size(self):
self.assertEqual(self.widget.size(), (50,50),
'incorrect default size')
def test_widget_resize(self):
self.widget.resize(100,150)
self.assertEqual(self.widget.size(), (100,150),
'wrong size after resize')
注解
各种测试的运行顺序是通过对测试方法名称按照字符串的内置排序进行排序来确定的。
如果在测试运行时 setUp()
方法引发异常,框架将认为测试发生了错误,并且不会执行测试方法。
类似地,我们可以提供一个 tearDown()
方法,该方法在测试方法运行后进行清理
import unittest
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def tearDown(self):
self.widget.dispose()
如果 setUp()
成功,则无论测试方法是否成功,都将运行 tearDown()
。
用于测试代码的这种工作环境称为测试装置。创建一个新的 TestCase 实例,作为用于执行每个单独测试方法的唯一测试装置。因此,setUp()
、tearDown()
和 __init__()
将每个测试调用一次。
建议您使用 TestCase 实现来根据它们测试的功能将测试组合在一起。unittest
提供了一种机制:测试套件,由 unittest
的 TestSuite
类表示。在大多数情况下,调用 unittest.main()
将会做正确的事情,并为您收集模块的所有测试用例并执行它们。
但是,如果您想自定义测试套件的构建,则可以自己完成
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase('test_default_widget_size'))
suite.addTest(WidgetTestCase('test_widget_resize'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
您可以将测试用例和测试套件的定义放在与要测试的代码相同的模块中(例如 widget.py
),但是将测试代码放在单独的模块中(例如 test_widget.py
)有几个优点
测试模块可以从命令行独立运行。
测试代码可以更容易地与发布的代码分离。
在没有充分理由的情况下,更改测试代码以适应其测试的代码的诱惑较小。
测试代码的修改频率应远低于其测试的代码。
可以更轻松地重构被测试的代码。
无论如何,用 C 编写的模块的测试必须在单独的模块中,那么为什么不保持一致呢?
如果测试策略发生变化,则无需更改源代码。
重用旧的测试代码¶
一些用户会发现他们有现有的测试代码,他们希望从 unittest
运行,而无需将每个旧的测试函数转换为 TestCase
子类。
因此,unittest
提供了一个 FunctionTestCase
类。此 TestCase
的子类可用于包装现有的测试函数。还可以提供设置和拆卸函数。
给定以下测试函数
def testSomething():
something = makeSomething()
assert something.name is not None
# ...
可以按如下方式创建等效的测试用例实例,并带有可选的设置和拆卸方法
testcase = unittest.FunctionTestCase(testSomething,
setUp=makeSomethingDB,
tearDown=deleteSomethingDB)
注解
即使可以使用 FunctionTestCase
将现有的测试库快速转换为基于 unittest
的系统,也不建议使用这种方法。花时间设置正确的 TestCase
子类将使将来的测试重构变得无限容易。
在某些情况下,现有测试可能已使用 doctest
模块编写。如果是这样,doctest
提供了一个 DocTestSuite
类,可以从现有的基于 doctest
的测试中自动构建 unittest.TestSuite
实例。
跳过测试和预期失败¶
在 3.1 版本中添加。
Unittest 支持跳过单个测试方法,甚至整个测试类。此外,它还支持将测试标记为“预期失败”,这是一种已损坏并将失败的测试,但不应将其计为 TestResult
上的失败。
跳过测试只是使用 skip()
装饰器 或其条件变体之一,调用 TestCase.skipTest()
在 setUp()
或测试方法中,或直接引发 SkipTest
。
基本的跳过如下所示
class MyTestCase(unittest.TestCase):
@unittest.skip("demonstrating skipping")
def test_nothing(self):
self.fail("shouldn't happen")
@unittest.skipIf(mylib.__version__ < (1, 3),
"not supported in this library version")
def test_format(self):
# Tests that work for only a certain version of the library.
pass
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_windows_support(self):
# windows specific testing code
pass
def test_maybe_skipped(self):
if not external_resource_available():
self.skipTest("external resource not available")
# test code that depends on the external resource
pass
这是在详细模式下运行上述示例的输出
test_format (__main__.MyTestCase.test_format) ... skipped 'not supported in this library version'
test_nothing (__main__.MyTestCase.test_nothing) ... skipped 'demonstrating skipping'
test_maybe_skipped (__main__.MyTestCase.test_maybe_skipped) ... skipped 'external resource not available'
test_windows_support (__main__.MyTestCase.test_windows_support) ... skipped 'requires Windows'
----------------------------------------------------------------------
Ran 4 tests in 0.005s
OK (skipped=4)
可以像方法一样跳过类
@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
def test_not_run(self):
pass
TestCase.setUp()
也可以跳过测试。当需要设置的资源不可用时,这很有用。
预期失败使用 expectedFailure()
装饰器。
class ExpectedFailureTestCase(unittest.TestCase):
@unittest.expectedFailure
def test_fail(self):
self.assertEqual(1, 0, "broken")
通过创建一个在想要跳过测试时在测试上调用 skip()
的装饰器,可以轻松地推出自己的跳过装饰器。此装饰器会跳过测试,除非传递的对象具有某个属性
def skipUnlessHasattr(obj, attr):
if hasattr(obj, attr):
return lambda func: func
return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))
以下装饰器和异常实现测试跳过和预期失败
- @unittest.skip(reason)¶
无条件跳过被装饰的测试。reason 应该描述为什么跳过测试。
- @unittest.skipIf(condition, reason)¶
如果 condition 为真,则跳过被装饰的测试。
- @unittest.skipUnless(condition, reason)¶
除非 condition 为真,否则跳过被装饰的测试。
- @unittest.expectedFailure¶
将测试标记为预期的失败或错误。 如果测试在测试函数本身(而不是在其中一个 测试夹具 方法中)失败或出错,则将其视为成功。 如果测试通过,则将其视为失败。
- exception unittest.SkipTest(reason)¶
抛出此异常以跳过测试。
通常,您可以使用
TestCase.skipTest()
或跳过装饰器之一,而不是直接抛出此异常。
跳过的测试将不会在其周围运行 setUp()
或 tearDown()
。 跳过的类将不会运行 setUpClass()
或 tearDownClass()
。 跳过的模块将不会运行 setUpModule()
或 tearDownModule()
。
使用子测试区分测试迭代¶
在 3.4 版本中添加。
当您的测试之间存在很小的差异时,例如某些参数,unittest 允许您使用 subTest()
上下文管理器在测试方法的主体中区分它们。
例如,以下测试
class NumbersTest(unittest.TestCase):
def test_even(self):
"""
Test that numbers between 0 and 5 are all even.
"""
for i in range(0, 6):
with self.subTest(i=i):
self.assertEqual(i % 2, 0)
将产生以下输出
======================================================================
FAIL: test_even (__main__.NumbersTest.test_even) (i=1)
Test that numbers between 0 and 5 are all even.
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 11, in test_even
self.assertEqual(i % 2, 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0
======================================================================
FAIL: test_even (__main__.NumbersTest.test_even) (i=3)
Test that numbers between 0 and 5 are all even.
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 11, in test_even
self.assertEqual(i % 2, 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0
======================================================================
FAIL: test_even (__main__.NumbersTest.test_even) (i=5)
Test that numbers between 0 and 5 are all even.
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 11, in test_even
self.assertEqual(i % 2, 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0
如果不使用子测试,执行会在第一次失败后停止,并且错误将更难以诊断,因为不会显示 i
的值
======================================================================
FAIL: test_even (__main__.NumbersTest.test_even)
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 32, in test_even
self.assertEqual(i % 2, 0)
AssertionError: 1 != 0
类和函数¶
本节深入描述 unittest
的 API。
测试用例¶
- class unittest.TestCase(methodName='runTest')¶
TestCase
类的实例表示unittest
世界中的逻辑测试单元。 此类旨在用作基类,并通过具体的子类实现特定的测试。 此类实现了测试运行器驱动测试所需的接口,以及测试代码可以用来检查和报告各种失败的方法。每个
TestCase
实例将运行一个基本方法:名为 methodName 的方法。 在TestCase
的大多数用法中,您既不会更改 methodName 也不会重新实现默认的runTest()
方法。TestCase
实例提供三组方法:一组用于运行测试,另一组用于测试实现以检查条件和报告失败,以及一些查询方法,允许收集有关测试本身的信息。第一组(运行测试)中的方法是
- setUp()¶
调用以准备测试夹具的方法。 这在调用测试方法之前立即调用; 除了
AssertionError
或SkipTest
,此方法引发的任何异常都将被视为错误而不是测试失败。 默认实现不执行任何操作。
- tearDown()¶
在调用测试方法并记录结果后立即调用的方法。 即使测试方法引发了异常,也会调用此方法,因此子类中的实现可能需要特别注意检查内部状态。 除了
AssertionError
或SkipTest
之外,此方法引发的任何异常都将被视为附加错误而不是测试失败(因此会增加报告错误的总数)。 无论测试方法的结果如何,只有在setUp()
成功时,才会调用此方法。 默认实现不执行任何操作。
- setUpClass()¶
在运行单个类中的测试之前调用的类方法。
setUpClass
使用类作为唯一参数调用,并且必须被装饰为classmethod()
@classmethod def setUpClass(cls): ...
有关详细信息,请参见 类和模块夹具。
在 3.2 版本中新增。
- tearDownClass()¶
在单个类中的测试运行后调用的类方法。
tearDownClass
使用类作为唯一参数调用,并且必须被装饰为classmethod()
@classmethod def tearDownClass(cls): ...
有关详细信息,请参见 类和模块夹具。
在 3.2 版本中新增。
- run(result=None)¶
运行测试,将结果收集到作为 result 传递的
TestResult
对象中。 如果省略 result 或为None
,则会创建一个临时结果对象(通过调用defaultTestResult()
方法)并使用。 结果对象返回给run()
的调用者。只需调用
TestCase
实例即可获得相同的效果。3.3 版本已更改:
run
的先前版本不返回结果。调用实例也不返回结果。
- subTest(msg=None, **params)¶
返回一个上下文管理器,它将封闭的代码块作为子测试执行。msg 和 params 是可选的,任意的值,当子测试失败时会显示这些值,以便您可以清楚地识别它们。
一个测试用例可以包含任意数量的子测试声明,并且它们可以任意嵌套。
有关更多信息,请参见 使用子测试区分测试迭代。
在 3.4 版本中添加。
- debug()¶
运行测试而不收集结果。这允许测试引发的异常传播到调用者,并且可以用于支持在调试器下运行测试。
TestCase
类提供了几个断言方法来检查和报告失败。下表列出了最常用的方法(有关更多断言方法,请参见下表)方法
检查
新增于
a == b
a != b
bool(x) is True
bool(x) is False
a is b
3.1
a is not b
3.1
x is None
3.1
x is not None
3.1
a in b
3.1
a not in b
3.1
isinstance(a, b)
3.2
not isinstance(a, b)
3.2
所有断言方法都接受一个 msg 参数,如果指定了该参数,则在失败时用作错误消息(另请参见
longMessage
)。请注意,msg 关键字参数只能在用作上下文管理器时传递给assertRaises()
,assertRaisesRegex()
,assertWarns()
,assertWarnsRegex()
。- assertEqual(first, second, msg=None)¶
测试 first 和 second 是否相等。如果值不相等,则测试将失败。
此外,如果 first 和 second 是完全相同的类型,并且是 list、tuple、dict、set、frozenset 或 str 中的一种,或者任何子类使用
addTypeEqualityFunc()
注册的类型,则会调用特定于类型的相等函数,以便生成更有用的默认错误消息(另请参见 特定于类型的方法列表)。3.1 版本已更改: 添加了自动调用特定于类型的相等函数。
3.2 版本已更改: 添加了
assertMultiLineEqual()
作为比较字符串的默认类型相等函数。
- assertNotEqual(first, second, msg=None)¶
测试 first 和 second 是否不相等。如果值比较相等,则测试将失败。
- 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)¶
测试 first 和 second 是否是(或不是)同一个对象。
在 3.1 版本中添加。
- assertIn(member, container, msg=None)¶
- assertNotIn(member, container, msg=None)¶
测试 member 是否在 container 中(或不在其中)。
在 3.1 版本中添加。
- assertIsInstance(obj, cls, msg=None)¶
- assertNotIsInstance(obj, cls, msg=None)¶
测试 obj 是否(或不是)cls 的实例(cls 可以是一个类或一个类元组,由
isinstance()
支持)。要检查确切的类型,请使用assertIs(type(obj), cls)
。在 3.2 版本中新增。
还可以使用以下方法检查异常、警告和日志消息的产生
方法
检查
新增于
fun(*args, **kwds)
抛出 excfun(*args, **kwds)
抛出 exc 并且消息与正则表达式 r 匹配3.1
fun(*args, **kwds)
抛出 warn3.2
fun(*args, **kwds)
抛出 warn 并且消息与正则表达式 r 匹配3.2
with
代码块在 logger 上记录,最低级别为 level3.4
with
代码块不在logger 上记录,最低级别为 level
3.10
- assertRaises(exception, callable, *args, **kwds)¶
- assertRaises(exception, *, msg=None)
测试当使用任何位置或关键字参数调用 callable 时,是否会抛出异常,这些参数也会传递给
assertRaises()
。如果抛出 exception 则测试通过,如果抛出其他异常则是错误,如果没有抛出异常则测试失败。要捕获一组异常中的任何一个,可以将包含异常类的元组作为 exception 传递。如果仅给出 exception 且可能给出 msg 参数,则返回上下文管理器,以便可以内联编写被测试的代码而不是作为函数
with self.assertRaises(SomeException): do_something()
当用作上下文管理器时,
assertRaises()
接受附加的关键字参数 msg。上下文管理器将捕获的异常对象存储在其
exception
属性中。 如果目的是对引发的异常执行其他检查,这将很有用with self.assertRaises(SomeException) as cm: do_something() the_exception = cm.exception self.assertEqual(the_exception.error_code, 3)
在 3.1 版本中更改: 增加了使用
assertRaises()
作为上下文管理器的功能。在 3.2 版本中更改: 添加了
exception
属性。在 3.3 版本中更改: 当用作上下文管理器时,添加了 msg 关键字参数。
- assertRaisesRegex(exception, regex, callable, *args, **kwds)¶
- assertRaisesRegex(exception, regex, *, msg=None)
类似于
assertRaises()
,但还测试 regex 是否与抛出的异常的字符串表示形式匹配。regex 可以是正则表达式对象或包含适用于re.search()
的正则表达式的字符串。示例self.assertRaisesRegex(ValueError, "invalid literal for.*XYZ'$", int, 'XYZ')
或者
with self.assertRaisesRegex(ValueError, 'literal'): int('XYZ')
在 3.1 版本中新增: 以
assertRaisesRegexp
名称添加。在 3.2 版本中更改: 重命名为
assertRaisesRegex()
。在 3.3 版本中更改: 当用作上下文管理器时,添加了 msg 关键字参数。
- assertWarns(warning, callable, *args, **kwds)¶
- assertWarns(warning, *, msg=None)
测试当使用任何位置或关键字参数调用 callable 时,是否会触发警告,这些参数也会传递给
assertWarns()
。如果触发了 warning 则测试通过,如果没有触发则测试失败。任何异常都是错误。要捕获一组警告中的任何一个,可以将包含警告类的元组作为 warnings 传递。如果仅给出 warning 且可能给出 msg 参数,则返回上下文管理器,以便可以内联编写被测试的代码而不是作为函数
with self.assertWarns(SomeWarning): do_something()
当用作上下文管理器时,
assertWarns()
接受附加的关键字参数 msg。上下文管理器将捕获的警告对象存储在其
warning
属性中,并将触发警告的源代码行存储在filename
和lineno
属性中。 如果目的是对捕获的警告执行其他检查,这将很有用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
代码块内发出的至少一条消息与 logger 和 level 条件匹配,则测试通过,否则测试失败。上下文管理器返回的对象是一个记录辅助工具,它会跟踪匹配的日志消息。它有两个属性:
- records¶
匹配的日志消息的
logging.LogRecord
对象列表。
示例
with self.assertLogs('foo', level='INFO') as cm: logging.getLogger('foo').info('first message') logging.getLogger('foo.bar').error('second message') self.assertEqual(cm.output, ['INFO:foo:first message', 'ERROR:foo.bar:second message'])
在 3.4 版本中添加。
- assertNoLogs(logger=None, level=None)¶
一个上下文管理器,用于测试在 logger 或其子项上是否没有记录消息,且该消息的级别至少为给定的 level。
如果给定,logger 应该是一个
logging.Logger
对象,或者是一个给出日志记录器名称的str
。默认值是根日志记录器,它将捕获所有消息。如果给定,level 应该是一个数字日志级别或其字符串等效项(例如,
"ERROR"
或logging.ERROR
)。默认值是logging.INFO
。与
assertLogs()
不同,上下文管理器不会返回任何内容。在 3.10 版本中新增。
还有其他一些用于执行更具体检查的方法,例如:
方法
检查
新增于
round(a-b, 7) == 0
round(a-b, 7) != 0
a > b
3.1
a >= b
3.1
a < b
3.1
a <= b
3.1
r.search(s)
3.1
not r.search(s)
3.2
a 和 b 具有相同数量的相同元素,而无需考虑顺序。
3.2
- assertAlmostEqual(first, second, places=7, msg=None, delta=None)¶
- assertNotAlmostEqual(first, second, places=7, msg=None, delta=None)¶
通过计算差值、四舍五入到给定的小数位数 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 版本中添加。
- 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 相同的元素,而忽略它们的顺序。如果它们不相同,将生成一个错误消息,列出序列之间的差异。
在比较 first 和 second 时,重复的元素不会被忽略。它验证每个元素在两个序列中是否具有相同的计数。等效于:
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()
自动使用的类型特定方法的列表。请注意,通常不需要直接调用这些方法。方法
用于比较
新增于
字符串
3.1
序列
3.1
列表
3.1
元组
3.1
集合或冻结集合
3.1
字典
3.1
- assertMultiLineEqual(first, second, msg=None)¶
测试多行字符串 first 是否等于字符串 second。如果不相等,则会在错误消息中包含两个字符串的差异,突出显示差异。默认情况下,当使用
assertEqual()
比较字符串时,会使用此方法。在 3.1 版本中添加。
- assertSequenceEqual(first, second, msg=None, seq_type=None)¶
测试两个序列是否相等。如果提供了 seq_type,则 first 和 second 都必须是 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()
比较集合或冻结集合时,会使用此方法。如果 first 或 second 都没有
set.difference()
方法,则会失败。在 3.1 版本中添加。
- assertDictEqual(first, second, msg=None)¶
测试两个字典是否相等。如果不相等,则会构造一条错误消息,显示字典中的差异。默认情况下,此方法将用于在调用
assertEqual()
时比较字典。在 3.1 版本中添加。
最后,
TestCase
提供了以下方法和属性- fail(msg=None)¶
无条件地发出测试失败信号,错误消息为 msg 或
None
。
- failureException¶
此类属性给出测试方法引发的异常。如果测试框架需要使用特定的异常,可能需要携带其他信息,它必须对该异常进行子类化,以便与框架“公平竞争”。此属性的初始值为
AssertionError
。
- longMessage¶
此类属性确定当自定义失败消息作为 msg 参数传递给失败的 assertXYY 调用时会发生什么。
True
是默认值。在这种情况下,自定义消息会附加到标准失败消息的末尾。当设置为False
时,自定义消息会替换标准消息。可以通过在调用 assert 方法之前将实例属性 self.longMessage 分配给
True
或False
,在单个测试方法中覆盖类设置。类设置在每次测试调用之前都会重置。
在 3.1 版本中添加。
- maxDiff¶
此属性控制断言方法在失败时报告差异输出的最大长度。默认值为 80*8 个字符。受此属性影响的断言方法包括
assertSequenceEqual()
(包括所有委托给它的序列比较方法),assertDictEqual()
和assertMultiLineEqual()
。将
maxDiff
设置为None
表示差异输出没有最大长度限制。在 3.2 版本中新增。
测试框架可以使用以下方法来收集测试信息
- defaultTestResult()¶
返回应用于此测试用例类的测试结果类的实例(如果没有其他结果实例提供给
run()
方法)。对于
TestCase
实例,这始终是TestResult
的实例;TestCase
的子类应根据需要覆盖此方法。
- id()¶
返回一个字符串,标识特定的测试用例。这通常是测试方法的完整名称,包括模块和类名称。
- shortDescription()¶
返回测试的描述,如果没有提供描述,则返回
None
。此方法的默认实现返回测试方法的文档字符串的第一行(如果可用),否则返回None
。在 3.1 版本中更改: 在 3.1 版本中,即使存在文档字符串,也会将测试名称添加到简短描述中。这导致了与 unittest 扩展的兼容性问题,并将测试名称添加到
TextTestResult
(在 Python 3.2 中)。
- addCleanup(function, /, *args, **kwargs)¶
添加一个函数,在
tearDown()
之后调用,以清理测试期间使用的资源。函数将按照它们添加的相反顺序(后进先出 LIFO)调用。调用时,会将传递给addCleanup()
的任何参数和关键字参数传递给它们。如果
setUp()
失败,这意味着不会调用tearDown()
,那么添加的任何清理函数仍将被调用。在 3.1 版本中添加。
- enterContext(cm)¶
进入提供的 上下文管理器。如果成功,还会通过
addCleanup()
将其__exit__()
方法添加为清理函数,并返回__enter__()
方法的结果。3.11 版本新增。
- doCleanups()¶
此方法在
tearDown()
之后或在setUp()
引发异常后无条件调用。它负责调用由
addCleanup()
添加的所有清理函数。如果您需要清理函数在tearDown()
之前 调用,那么您可以自己调用doCleanups()
。doCleanups()
逐个弹出清理函数堆栈中的方法,因此可以随时调用。在 3.1 版本中添加。
- classmethod addClassCleanup(function, /, *args, **kwargs)¶
添加一个函数,在
tearDownClass()
之后调用,以清理测试类期间使用的资源。函数将按照它们添加的相反顺序(后进先出 LIFO)调用。调用时,会将传递给addClassCleanup()
的任何参数和关键字参数传递给它们。如果
setUpClass()
失败,这意味着不会调用tearDownClass()
,那么添加的任何清理函数仍将被调用。3.8 版本新增。
- classmethod enterClassContext(cm)¶
进入提供的 上下文管理器。如果成功,还会通过
addClassCleanup()
将其__exit__()
方法添加为清理函数,并返回__enter__()
方法的结果。3.11 版本新增。
- classmethod doClassCleanups()¶
此方法在
tearDownClass()
之后或在setUpClass()
引发异常后无条件调用。它负责调用所有由
addClassCleanup()
添加的清理函数。 如果您需要在tearDownClass()
之前 调用清理函数,那么您可以自己调用doClassCleanups()
。doClassCleanups()
每次从清理函数堆栈中弹出一个方法,因此可以随时调用它。3.8 版本新增。
- class unittest.IsolatedAsyncioTestCase(methodName='runTest')¶
此类提供类似于
TestCase
的 API,并且还接受协程作为测试函数。3.8 版本新增。
- loop_factory¶
传递给
asyncio.Runner
的 loop_factory。在子类中使用asyncio.EventLoop
覆盖,以避免使用 asyncio 策略系统。在 3.13 版本中添加。
- coroutine asyncSetUp()¶
调用此方法来准备测试夹具。它在
setUp()
之后调用。它在调用测试方法之前立即调用;除了AssertionError
或SkipTest
之外,此方法引发的任何异常都将被视为错误而不是测试失败。默认实现不执行任何操作。
- coroutine asyncTearDown()¶
在测试方法被调用且结果被记录后立即调用的方法。它在
tearDown()
之前调用。即使测试方法引发了异常也会调用此方法,因此子类中的实现可能需要特别小心地检查内部状态。此方法引发的任何异常,除了AssertionError
或SkipTest
之外,都将被视为额外的错误,而不是测试失败(从而增加报告的错误总数)。只有在asyncSetUp()
成功时才会调用此方法,无论测试方法的结果如何。默认实现不执行任何操作。
- addAsyncCleanup(function, /, *args, **kwargs)¶
此方法接受可用作清理函数的协程。
- coroutine enterAsyncContext(cm)¶
进入提供的异步上下文管理器。如果成功,还会通过
addAsyncCleanup()
将其__aexit__()
方法添加为清理函数,并返回__aenter__()
方法的结果。3.11 版本新增。
- run(result=None)¶
设置一个新的事件循环来运行测试,将结果收集到作为 result 传递的
TestResult
对象中。如果省略 result 或 result 为None
,则会创建一个临时结果对象(通过调用defaultTestResult()
方法)并使用。结果对象将返回给run()
的调用者。在测试结束时,事件循环中的所有任务都将被取消。
一个说明顺序的示例
from unittest import IsolatedAsyncioTestCase events = [] class Test(IsolatedAsyncioTestCase): def setUp(self): events.append("setUp") async def asyncSetUp(self): self._async_connection = await AsyncConnection() events.append("asyncSetUp") async def test_response(self): events.append("test_response") response = await self._async_connection.get("https://example.com") self.assertEqual(response.status_code, 200) self.addAsyncCleanup(self.on_cleanup) def tearDown(self): events.append("tearDown") async def asyncTearDown(self): await self._async_connection.close() events.append("asyncTearDown") async def on_cleanup(self): events.append("cleanup") if __name__ == "__main__": unittest.main()
运行测试后,
events
将包含["setUp", "asyncSetUp", "test_response", "asyncTearDown", "tearDown", "cleanup"]
。
分组测试¶
- class unittest.TestSuite(tests=())¶
此类表示单个测试用例和测试套件的聚合。此类提供测试运行器所需的接口,以允许其像任何其他测试用例一样运行。运行
TestSuite
实例与迭代套件并单独运行每个测试相同。如果给定 tests,它必须是一个由单个测试用例或其他测试套件组成的可迭代对象,这些对象将用于最初构建套件。还提供了其他方法来稍后向集合中添加测试用例和套件。
TestSuite
对象行为很像TestCase
对象,但它们实际上并不实现测试。相反,它们用于将测试聚合到应一起运行的测试组中。一些其他方法可用于向TestSuite
实例添加测试- 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()
来恢复该行为。
加载和运行测试¶
- class unittest.TestLoader¶
TestLoader
类用于从类和模块创建测试套件。通常,无需创建此类的实例;unittest
模块提供了一个可以共享的实例,即unittest.defaultTestLoader
。 但是,使用子类或实例可以自定义某些可配置的属性。TestLoader
对象具有以下属性- errors¶
加载测试时遇到的非致命错误列表。加载器在任何时候都不会重置此列表。致命错误通过相关方法向调用者引发异常来发出信号。非致命错误也由一个合成测试指示,该测试在运行时将引发原始错误。
3.5 版本新增。
TestLoader
对象具有以下方法- loadTestsFromTestCase(testCaseClass)¶
返回
TestCase
派生的testCaseClass
中包含的所有测试用例的套件。为
getTestCaseNames()
命名的每个方法创建一个测试用例实例。 默认情况下,这些是以test
开头的方法名称。 如果getTestCaseNames()
没有返回任何方法,但实现了runTest()
方法,则会为该方法创建一个测试用例。
- loadTestsFromModule(module, *, pattern=None)¶
返回给定模块中包含的所有测试用例的套件。此方法在 module 中搜索从
TestCase
派生的类,并为该类定义的每个测试方法创建该类的一个实例。注解
虽然使用
TestCase
派生类的层次结构可以方便地共享 fixtures 和辅助函数,但在不打算直接实例化的基类上定义测试方法并不适用于此方法。但是,当 fixtures 不同且在子类中定义时,这样做可能很有用。如果模块提供了
load_tests
函数,则将调用该函数来加载测试。这允许模块自定义测试加载。这是load_tests 协议。 pattern 参数作为第三个参数传递给load_tests
。在 3.2 版本中变更: 添加了对
load_tests
的支持。在 3.5 版本中变更: 已添加对仅关键字参数 pattern 的支持。
在 3.12 版本中变更: 已删除未记录和非官方的 use_load_tests 参数。
- loadTestsFromName(name, module=None)¶
返回给定字符串说明符的所有测试用例的套件。
说明符 name 是一个“点式名称”,可以解析为模块、测试用例类、测试用例类中的测试方法、
TestSuite
实例,或返回TestCase
或TestSuite
实例的可调用对象。 这些检查按照此处列出的顺序应用;也就是说,一个可能的测试用例类上的方法将被视为“测试用例类中的测试方法”,而不是“可调用对象”。例如,如果您有一个模块
SampleTests
,其中包含一个TestCase
派生的类SampleTestCase
,其中包含三个测试方法(test_one()
、test_two()
和test_three()
),说明符'SampleTests.SampleTestCase'
将导致此方法返回一个将运行所有三个测试方法的套件。 使用说明符'SampleTests.SampleTestCase.test_two'
将导致它返回一个仅运行test_two()
测试方法的测试套件。 说明符可以引用尚未导入的模块和包;它们将作为副作用导入。该方法可以选择相对于给定的模块解析名称。
在 3.5 版本中变更: 如果在遍历 name 时发生
ImportError
或AttributeError
,则将返回一个合成测试,该测试在运行时会引发该错误。 这些错误会包含在 self.errors 累积的错误中。
- loadTestsFromNames(names, module=None)¶
类似于
loadTestsFromName()
,但接受的是名称序列而不是单个名称。返回值是一个测试套件,它支持为每个名称定义的所有测试。
- discover(start_dir, pattern='test*.py', top_level_dir=None)¶
通过从指定的起始目录递归进入子目录来查找所有测试模块,并返回一个包含它们的 TestSuite 对象。只会加载与 pattern 匹配的测试文件。(使用 shell 样式模式匹配。)只会加载可导入的模块名称(即有效的 Python 标识符)。
所有测试模块都必须可以从项目的顶层导入。如果起始目录不是顶层目录,则必须单独指定 top_level_dir。
如果导入模块失败,例如由于语法错误,则会将其记录为单个错误,并且发现将继续。如果导入失败是由于引发了
SkipTest
,则会将其记录为跳过而不是错误。如果找到一个包(包含名为
__init__.py
的文件的目录),则会检查该包中是否存在load_tests
函数。如果存在此函数,则将调用package.load_tests(loader, tests, pattern)
。测试发现会注意确保在一次调用期间仅对包检查一次测试,即使 load_tests 函数本身调用loader.discover
。如果
load_tests
存在,则发现不会递归进入包,load_tests
负责加载包中的所有测试。该模式被特意不存储为加载器属性,以便包可以继续自行发现。
top_level_dir 在内部存储,并用作对
discover()
的任何嵌套调用的默认值。也就是说,如果包的load_tests
调用loader.discover()
,则不需要传递此参数。start_dir 可以是虚线模块名称以及目录。
在 3.2 版本中新增。
在 3.4 版本中变更: 导入时引发
SkipTest
的模块会记录为跳过,而不是错误。在 3.4 版本中变更: start_dir 可以是 命名空间包。
在 3.4 版本中变更: 路径在导入之前进行排序,以便即使底层文件系统的顺序不依赖于文件名,执行顺序也相同。
在 3.5 版本中变更: 现在,无论找到的包的路径是否与 pattern 匹配,都会检查这些包是否存在
load_tests
,因为包名称不可能与默认模式匹配。在 3.11 版本中变更: start_dir 不能是 命名空间包。自 Python 3.7 以来,它已被破坏,Python 3.11 正式将其删除。
在 3.13 版本中变更: top_level_dir 仅在 discover 调用的持续时间内存储。
TestLoader
的以下属性可以通过子类化或在实例上赋值来配置- testMethodPrefix¶
字符串,给出将被解释为测试方法的方法名称的前缀。默认值为
'test'
。这会影响
getTestCaseNames()
和所有loadTestsFrom*
方法。
- sortTestMethodsUsing¶
在
getTestCaseNames()
和所有loadTestsFrom*
方法中排序方法名称时要使用的比较函数。
- testNamePatterns¶
Unix shell 样式通配符测试名称模式列表,测试方法必须匹配这些模式才能包含在测试套件中(请参见
-k
选项)。如果此属性不是
None
(默认值),则要包含在测试套件中的所有测试方法都必须匹配此列表中的一个模式。请注意,匹配始终使用fnmatch.fnmatchcase()
执行,因此与传递给-k
选项的模式不同,简单的子字符串模式必须使用*
通配符进行转换。这会影响所有
loadTestsFrom*
方法。3.7 版本新增。
- class unittest.TestResult¶
此类用于编译有关哪些测试成功和哪些测试失败的信息。
TestResult
对象存储一组测试的结果。TestCase
和TestSuite
类确保正确记录结果;测试编写者无需担心记录测试的结果。构建在
unittest
之上的测试框架可能需要访问通过运行一组测试生成的TestResult
对象以进行报告;为此目的,TestRunner.run()
方法返回一个TestResult
实例。TestResult
实例具有以下属性,这些属性在检查运行一组测试的结果时会很有用- failures¶
一个列表,包含
TestCase
实例和包含格式化回溯的字符串的 2 元组。每个元组表示使用 assert* 方法 明确发出失败信号的测试。
- collectedDurations¶
一个列表,其中包含测试用例名称和浮点数的 2 元组,表示每个运行的测试的经过时间。
在 3.12 版本中新增。
- testsRun¶
到目前为止运行的测试总数。
- buffer¶
如果设置为 true,则在
startTest()
和stopTest()
被调用之间,sys.stdout
和sys.stderr
将被缓冲。只有当测试失败或出错时,收集到的输出才会回显到真实的sys.stdout
和sys.stderr
。任何输出也会附加到失败/错误消息中。在 3.2 版本中新增。
- tb_locals¶
如果设置为 true,则局部变量将显示在回溯中。
3.5 版本新增。
- wasSuccessful()¶
如果到目前为止运行的所有测试都通过了,则返回
True
,否则返回False
。在 3.4 版本中更改:如果来自使用
expectedFailure()
装饰器标记的测试中存在任何unexpectedSuccesses
,则返回False
。
- stop()¶
可以调用此方法来发出信号,表明应通过将
shouldStop
属性设置为True
来中止正在运行的测试集。TestRunner
对象应遵守此标志,并在不运行任何其他测试的情况下返回。例如,当用户从键盘发出中断信号时,
TextTestRunner
类使用此功能来停止测试框架。提供TestRunner
实现的交互式工具可以以类似的方式使用它。
TestResult
类的以下方法用于维护内部数据结构,并且可以在子类中扩展以支持其他报告要求。这在构建在测试运行时支持交互式报告的工具中特别有用。- startTest(test)¶
当测试用例 test 即将运行时调用。
- stopTest(test)¶
在测试用例 test 执行完毕后调用,无论结果如何。
- startTestRun()¶
在执行任何测试之前调用一次。
在 3.1 版本中添加。
- stopTestRun()¶
在所有测试执行完毕后调用一次。
在 3.1 版本中添加。
- addError(test, err)¶
当测试用例 test 引发意外异常时调用。err 是由
sys.exc_info()
返回的形式的元组:(type, value, traceback)
。默认实现将元组
(test, formatted_err)
附加到实例的errors
属性,其中 formatted_err 是从 err 导出的格式化回溯。
- addFailure(test, err)¶
当测试用例 test 发出失败信号时调用。err 是由
sys.exc_info()
返回的形式的元组:(type, value, traceback)
。默认实现将元组
(test, formatted_err)
附加到实例的failures
属性,其中 formatted_err 是从 err 导出的格式化回溯。
- addSuccess(test)¶
当测试用例 test 成功时调用。
默认实现不执行任何操作。
- addExpectedFailure(test, err)¶
当测试用例 test 失败或出错,但使用
expectedFailure()
装饰器标记时调用。默认实现将元组
(test, formatted_err)
附加到实例的expectedFailures
属性,其中 formatted_err 是从 err 导出的格式化回溯。
- addUnexpectedSuccess(test)¶
当测试用例 test 使用
expectedFailure()
装饰器标记,但成功时调用。默认实现将测试附加到实例的
unexpectedSuccesses
属性。
- addSubTest(test, subtest, outcome)¶
当子测试完成时调用。test 是对应于测试方法的测试用例。subtest 是一个自定义的
TestCase
实例,描述子测试。如果 outcome 为
None
,则子测试成功。否则,子测试失败,并抛出一个异常,其中 outcome 是由sys.exc_info()
返回的以下形式的元组:(type, value, traceback)
。默认实现会在结果成功时不执行任何操作,并将子测试失败记录为普通失败。
在 3.4 版本中添加。
- addDuration(test, elapsed)¶
在测试用例完成时调用。elapsed 是以秒为单位表示的时间,包括清理函数的执行时间。
在 3.12 版本中新增。
- class unittest.TextTestResult(stream, descriptions, verbosity, *, durations=None)¶
TextTestRunner
使用的TestResult
的具体实现。子类应接受**kwargs
以确保在接口更改时的兼容性。在 3.2 版本中新增。
3.12 版本中的更改: 添加了 durations 关键字参数。
- unittest.defaultTestLoader¶
旨在共享的
TestLoader
类的实例。如果不需要对TestLoader
进行自定义,可以使用此实例,而无需重复创建新实例。
- class unittest.TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, buffer=False, resultclass=None, warnings=None, *, tb_locals=False, durations=None)¶
一个基本的测试运行器实现,将结果输出到流。如果 stream 为
None
(默认值),则使用sys.stderr
作为输出流。此类有一些可配置的参数,但本质上非常简单。运行测试套件的图形应用程序应提供替代实现。当 unittest 添加功能时,此类实现应接受**kwargs
作为构造运行器的接口。默认情况下,此运行器显示
DeprecationWarning
、PendingDeprecationWarning
、ResourceWarning
和ImportWarning
,即使它们是 默认被忽略的。可以使用 Python 的-Wd
或-Wa
选项(请参阅 警告控制)并将 warnings 保留为None
来覆盖此行为。3.2 版本中的更改: 添加了 warnings 参数。
3.2 版本中的更改: 默认流在实例化时而不是在导入时设置为
sys.stderr
。3.5 版本中的更改: 添加了 tb_locals 参数。
3.12 版本中的更改: 添加了 durations 参数。
- _makeResult()¶
此方法返回
run()
使用的TestResult
的实例。它不打算直接调用,但可以在子类中重写以提供自定义的TestResult
。_makeResult()
实例化在TextTestRunner
构造函数中作为resultclass
参数传入的类或可调用对象。如果没有提供resultclass
,则默认为TextTestResult
。结果类使用以下参数实例化stream, descriptions, verbosity
- run(test)¶
此方法是
TextTestRunner
的主要公共接口。此方法接受TestSuite
或TestCase
实例。通过调用_makeResult()
创建一个TestResult
,并运行测试并将结果打印到 stdout。
- unittest.main(module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=unittest.defaultTestLoader, exit=True, verbosity=1, failfast=None, catchbreak=None, buffer=None, warnings=None)¶
一个命令行程序,从 module 加载一组测试并运行它们;这主要是为了使测试模块方便地执行。此函数最简单的用法是在测试脚本的末尾包含以下行
if __name__ == '__main__': unittest.main()
您可以通过传入 verbosity 参数来运行具有更详细信息的测试
if __name__ == '__main__': unittest.main(verbosity=2)
defaultTest 参数是单个测试的名称或要运行的测试名称的可迭代对象(如果未通过 argv 指定测试名称)。如果未指定或为
None
,并且未通过 argv 提供测试名称,则将运行 module 中找到的所有测试。argv 参数可以是传递给程序的选项列表,其中第一个元素是程序名称。如果未指定或为
None
,则使用sys.argv
的值。testRunner 参数可以是测试运行器类,也可以是其已创建的实例。默认情况下,
main
会调用sys.exit()
,并使用退出代码指示运行的测试是成功 (0) 还是失败 (1)。退出代码为 5 表示没有运行任何测试或跳过了测试。testLoader 参数必须是
TestLoader
的实例,默认值为defaultTestLoader
。通过传入参数
exit=False
,可以在交互式解释器中使用main
。这会在标准输出上显示结果,而不会调用sys.exit()
。>>> from unittest import main >>> main(module='test_module', exit=False)
failfast、catchbreak 和 buffer 参数的效果与同名的 命令行选项相同。
warnings 参数指定运行测试时应使用的警告过滤器。如果未指定,则当向 python 传递
-W
选项时,它将保持为None
(请参阅警告控制),否则它将设置为'default'
。调用
main
会返回一个对象,该对象的result
属性包含以unittest.TestResult
形式运行的测试结果。在 3.1 版本中更改:添加了 exit 参数。
在 3.2 版本中更改:添加了 verbosity、failfast、catchbreak、buffer 和 warnings 参数。
在 3.4 版本中更改:defaultTest 参数已更改为也接受测试名称的可迭代对象。
load_tests 协议¶
在 3.2 版本中新增。
模块或包可以通过实现一个名为 load_tests
的函数来自定义在正常测试运行或测试发现期间如何从中加载测试。
如果测试模块定义了 load_tests
,则 TestLoader.loadTestsFromModule()
将使用以下参数调用它
load_tests(loader, standard_tests, pattern)
其中 pattern 是直接从 loadTestsFromModule
传递的。它默认为 None
。
它应该返回一个 TestSuite
。
loader 是执行加载的 TestLoader
的实例。standard_tests 是默认情况下将从模块加载的测试。测试模块通常只希望从标准测试集中添加或删除测试。第三个参数用于在测试发现中加载包。
一个典型的从一组特定的 TestCase
类加载测试的 load_tests
函数可能如下所示
test_cases = (TestCase1, TestCase2, TestCase3)
def load_tests(loader, tests, pattern):
suite = TestSuite()
for test_class in test_cases:
tests = loader.loadTestsFromTestCase(test_class)
suite.addTests(tests)
return suite
如果从命令行或通过调用 TestLoader.discover()
在包含包的目录中启动发现,则将检查包 __init__.py
是否存在 load_tests
。如果该函数不存在,则发现将像递归到另一个目录一样递归到包中。否则,将由 load_tests
来进行包的测试发现,该函数将使用以下参数调用
load_tests(loader, standard_tests, pattern)
这应该返回一个表示包中所有测试的 TestSuite
。(standard_tests
只会包含从 __init__.py
收集的测试。)
因为模式被传递到 load_tests
中,所以包可以自由地继续(并可能修改)测试发现。一个“不做任何事”的测试包的 load_tests
函数如下所示
def load_tests(loader, standard_tests, pattern):
# top level directory cached on loader instance
this_dir = os.path.dirname(__file__)
package_tests = loader.discover(start_dir=this_dir, pattern=pattern)
standard_tests.addTests(package_tests)
return standard_tests
在 3.5 版本中更改:由于包名称不可能与默认模式匹配,因此发现不再检查与 pattern 匹配的包名称。
类和模块固定装置¶
类和模块级别的固定装置在 TestSuite
中实现。当测试套件遇到来自新类的测试时,会调用前一个类的 tearDownClass()
(如果存在),然后调用新类的 setUpClass()
。
类似地,如果测试来自与前一个测试不同的模块,则会运行前一个模块的 tearDownModule
,然后运行新模块的 setUpModule
。
在所有测试都运行完毕后,会运行最终的 tearDownClass
和 tearDownModule
。
请注意,共享固定装置与测试并行化等[潜在]功能不兼容,并且会破坏测试隔离。应谨慎使用它们。
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()
如果您希望调用基类上的 setUpClass
和 tearDownClass
,则必须自己调用它们。TestCase
中的实现为空。
如果在 setUpClass
期间引发了异常,则不会运行类中的测试,也不会运行 tearDownClass
。跳过的类将不会运行 setUpClass
或 tearDownClass
。如果异常是 SkipTest
异常,则该类将被报告为已跳过,而不是作为错误。
setUpModule 和 tearDownModule¶
它们应实现为函数
def setUpModule():
createConnection()
def tearDownModule():
closeConnection()
如果在 setUpModule
中引发了异常,则不会运行模块中的任何测试,也不会运行 tearDownModule
。如果异常是 SkipTest
异常,则该模块将被报告为已跳过,而不是作为错误。
要添加即使在出现异常的情况下也必须运行的清理代码,请使用 addModuleCleanup
- unittest.addModuleCleanup(function, /, *args, **kwargs)¶
添加一个函数,该函数将在
tearDownModule()
之后调用,以清理测试类期间使用的资源。 函数将按照添加顺序的反向顺序(LIFO)调用。当它们被添加时,会使用传递给addModuleCleanup()
的任何参数和关键字参数来调用它们。如果
setUpModule()
失败,意味着不会调用tearDownModule()
,那么任何添加的清理函数仍然会被调用。3.8 版本新增。
- classmethod unittest.enterModuleContext(cm)¶
进入提供的上下文管理器。如果成功,还会通过
addModuleCleanup()
将其__exit__()
方法添加为清理函数,并返回__enter__()
方法的结果。3.11 版本新增。
- unittest.doModuleCleanups()¶
此函数在
tearDownModule()
之后无条件调用,或者在setUpModule()
抛出异常后调用。它负责调用所有由
addModuleCleanup()
添加的清理函数。如果您需要在tearDownModule()
之前 调用清理函数,那么您可以自己调用doModuleCleanups()
。doModuleCleanups()
从清理函数堆栈中一次弹出一个方法,因此可以在任何时候调用。3.8 版本新增。
信号处理¶
在 3.2 版本中新增。
unittest 的 -c/--catch
命令行选项,以及 unittest.main()
的 catchbreak
参数,在测试运行期间提供了更友好的 control-C 处理。启用捕获中断行为后,control-C 将允许当前正在运行的测试完成,然后测试运行将结束并报告到目前为止的所有结果。第二次 control-c 将以通常的方式引发 KeyboardInterrupt
。
control-c 处理信号处理程序尝试与安装了自己的 signal.SIGINT
处理程序的代码或测试保持兼容。如果调用了 unittest
处理程序,但它不是已安装的 signal.SIGINT
处理程序,即它已被被测系统替换并委托,那么它会调用默认处理程序。这通常是替换已安装的处理程序并委托给它的代码所期望的行为。对于需要禁用 unittest
control-c 处理的单个测试,可以使用 removeHandler()
装饰器。
有一些实用函数供框架作者在测试框架中启用 control-c 处理功能。
- unittest.installHandler()¶
安装 control-c 处理程序。当收到
signal.SIGINT
时(通常是响应用户按下 control-c),所有已注册的结果都会调用stop()
。
- unittest.registerResult(result)¶
注册一个用于 control-c 处理的
TestResult
对象。注册结果会存储对它的弱引用,因此它不会阻止结果被垃圾回收。如果未启用 control-c 处理,注册
TestResult
对象没有副作用,因此测试框架可以无条件地注册它们创建的所有结果,而无需考虑是否启用了处理。
- unittest.removeHandler(function=None)¶
在不带参数的情况下调用此函数会删除已安装的 control-c 处理程序。此函数也可以用作测试装饰器,以便在执行测试时临时删除处理程序
@unittest.removeHandler def test_signal_handling(self): ...