25.3. unittest-单元测试框架
2.1 版中的新Function。
(如果您已经熟悉测试的基本概念,则可能要跳到assert 方法列表。)
Python 单元测试框架(有时也称为“ PyUnit”)是 Kent Beck 和 Erich Gamma 编写的 JUnit 的 Python 语言版本。反过来,JUnit 是 Kent 的 Smalltalk 测试框架的 Java 版本。每个都是针对其相应语言的事实上的标准单元测试框架。
unittest支持测试自动化,共享测试的设置和关闭代码,将测试聚合到集合中以及测试与报告框架的独立性。 unittest模块提供的类可轻松支持一组测试的这些质量。
为此,unittest支持一些重要概念:
-
test fixture
- 测试装置表示执行一个或多个测试所需的准备工作,以及任何相关的清理操作。例如,这可能涉及创建临时或代理数据库,目录或启动服务器进程。
-
test case
-
test suite
- 测试套件是测试用例,测试套件或两者的集合。它用于汇总应一起执行的测试。
-
test runner
- 测试运行程序是协调测试执行并向用户提供结果的组件。Running 者可以使用图形界面,文本界面,或返回特殊值以指示执行测试的结果。
passTestCase和FunctionTestCase类支持测试用例和测试夹具概念。在创建新测试时应使用前者,而在将现有测试代码与_3 驱动框架集成时,可以使用后者。使用TestCase构建测试夹具时,可以覆盖setUp()和tearDown()方法以提供夹具的初始化和清理。使用FunctionTestCase,可以将现有函数传递给构造函数以实现这些目的。运行测试时,首先运行夹具初始化;然后运行。如果成功,则无论测试结果如何,都将在执行测试后运行 cleanup 方法。 TestCase的每个实例将仅用于运行单个测试方法,因此将为每个测试创建一个新的夹具。
测试套件由TestSuite类实现。此类允许单个测试和测试套件的聚合;执行套件时,将运行直接添加到套件和“子”测试套件中的所有测试。
测试运行程序是提供单个方法run()
的对象,该方法接受TestCase或TestSuite对象作为参数,并返回结果对象。提供了TestResult类作为结果对象。 unittest提供了TextTestRunner作为示例测试运行程序,该运行程序默认情况下在标准错误流上报告测试结果。可以在其他环境(例如图形环境)中实现替代运行程序,而无需从特定类派生。
See also
25.3.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()
pass子类unittest.TestCase创建一个测试用例。这三个单独的测试使用名称以字母test
开头的方法定义。该命名约定将告知测试运行者哪些方法表示测试。
每个测试的症结在于调用assertEqual()以检查预期结果; assertTrue()或assertFalse()验证条件;或assertRaises()以验证是否引发了特定异常。使用这些方法代替assert语句,以便测试运行器可以累积所有测试结果并生成报告。
setUp()和tearDown()方法允许您定义将在每种测试方法之前和之后执行的指令。它们在组织测试代码部分中有更详细的介绍。
最后一块显示了一种运行测试的简单方法。 unittest.main()提供测试脚本的命令行界面。从命令行运行时,上面的脚本产生的输出看起来像这样:
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
除了unittest.main()以外,还有其他方法可以以更精细的控制级别,更简洁的输出以及无需从命令行运行的方式运行测试。例如,最后两行可以替换为:
suite = unittest.TestLoader().loadTestsFromTestCase(TestStringMethods)
unittest.TextTestRunner(verbosity=2).run(suite)
从解释器或其他脚本运行修订的脚本会产生以下输出:
test_isupper (__main__.TestStringMethods) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
上面的示例显示了最常用的unittestFunction,这些Function足以满足许多日常测试需求。本文档的其余部分从第一个原理探讨了完整的Function集。
25.3.2. 命令行界面
可以从命令行使用 unittest 模块从模块,类甚至单个测试方法运行测试:
python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
您可以传入一个列表,其中包含模块名称以及完全限定的类或方法名称的任意组合。
您可以pass传递-v 标志来运行更详细(更详细)的测试:
python -m unittest -v test_module
有关所有命令行选项的列表:
python -m unittest -h
在 2.7 版中进行了更改:在早期版本中,只能运行单独的测试方法,而不能运行模块或类。
25.3.2.1. 命令行选项
unittest 支持以下命令行选项:
-
-b
`,` `--buffer`
- 在测试运行期间,将缓冲标准输出和标准错误流。pass测试期间的输出将被丢弃。在测试失败或错误时,通常会回显输出,并将其添加到失败消息中。
-
-c
`,` `--catch`
- 在测试运行期间,Control-Cawait 当前测试结束,然后报告到目前为止的所有结果。第二个 Control-C 引发正常的KeyboardInterrupt异常。
有关提供此Function的Function,请参见Signal Handling。
-f
`,` `--failfast`
- 在第一个错误或失败时停止测试运行。
2.7 版中的新增Function:添加了命令行选项-b
,-c
和-f
。
命令行还可以用于测试发现,运行项目中的所有测试或仅运行子集。
25.3.3. 测试发现
2.7 版的新Function。
Unittest 支持简单的测试发现。为了与测试发现兼容,所有测试文件必须可以从项目的顶级目录导入modules或packages(这意味着它们的文件名必须为identifiers)。
测试发现在TestLoader.discover()中实现,但也可以从命令行使用。基本的命令行用法是:
cd project_directory
python -m unittest discover
discover
子命令具有以下选项:
-
-v
`,` `--verbose`
- Verbose output
-
-s
``,
--start-directory
directory
- 开始发现的目录(默认为
.
)
- 开始发现的目录(默认为
-
-p
``,
--pattern
pattern
- 模式以匹配测试文件(默认为
test*.py
)
- 模式以匹配测试文件(默认为
-
-t
``,
--top-level-directory
directory
- 项目的顶层目录(默认为起始目录)
-s,-p和-t选项可以按位置 Sequences 作为位置参数传递。以下两个命令行是等效的:
python -m unittest discover -s project_directory -p "*_test.py"
python -m unittest discover project_directory "*_test.py"
除了作为路径外,还可以将包名称(例如myproject.subpackage.test
)作为起始目录。然后,将提供您提供的软件包名称,并将其在文件系统上的位置用作起始目录。
Caution
测试发现pass导入来加载测试。一旦测试发现从开始目录中找到所有测试文件,您就可以指定将路径转换为要导入的程序包名称。例如foo/bar/baz.py
将被导入为foo.bar.baz
。
如果您已全局安装了一个软件包,并try在该软件包的另一个副本上进行测试发现,则导入可能从错误的位置进行。如果发生这种情况,测试发现将警告您并退出。
如果您以包名而不是目录路径的形式提供开始目录,那么 Discover 会假设它从哪个导入位置进入您想要的位置,因此不会收到警告。
测试模块和软件包可以passload_tests protocol自定义测试加载和发现。
25.3.4. 组织测试代码
单元测试的基本构建块是测试用例-必须设置单个场景并检查其正确性。在unittest中,测试用例由unittest的TestCase类的实例表示。要制作自己的测试用例,必须编写TestCase的子类,或使用FunctionTestCase。
TestCase派生类的实例是可以完全运行单个测试方法以及可选的设置和整理代码的对象。
TestCase实例的测试代码应完全独立,以便可以与任意数量的其他测试用例隔离运行或任意组合运行。
最简单的TestCase子类将简单地覆盖runTest()
方法以执行特定的测试代码:
import unittest
class DefaultWidgetSizeTestCase(unittest.TestCase):
def runTest(self):
widget = Widget('The widget')
self.assertEqual(widget.size(), (50, 50), 'incorrect default size')
请注意,为了测试某些内容,我们使用TestCaseBase Class 提供的assert*()
方法之一。如果测试失败,则会引发异常,并且unittest将测试用例标识为* failure 。其他任何异常都将被视为 errors *。这可以帮助您确定问题出在哪里:失败是由不正确的结果引起的-5 是您期望的 6.错误是由不正确的代码引起的-例如,由错误的函数调用引起的TypeError。
稍后将描述运行测试用例的方法。现在,请注意,要构造这种测试用例的实例,我们将其构造函数称为不带参数的:
testCase = DefaultWidgetSizeTestCase()
现在,这样的测试用例可能很多,并且它们的设置可能是重复的。在上述情况下,在 100 个 Widget 测试用例子类中的每个子类中构造Widget
将意味着难看的重复。
幸运的是,我们可以pass实现一个名为setUp()的方法来排除此类设置代码,测试框架将在运行测试时自动调用我们:
import unittest
class SimpleWidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
class DefaultWidgetSizeTestCase(SimpleWidgetTestCase):
def runTest(self):
self.assertEqual(self.widget.size(), (50,50),
'incorrect default size')
class WidgetResizeTestCase(SimpleWidgetTestCase):
def runTest(self):
self.widget.resize(100,150)
self.assertEqual(self.widget.size(), (100,150),
'wrong size after resize')
如果在运行测试时setUp()方法引发异常,则框架将认为测试已出错,并且将不执行runTest()
方法。
同样,我们可以提供一种tearDown()方法,该方法在运行runTest()
方法后会整理:
import unittest
class SimpleWidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def tearDown(self):
self.widget.dispose()
self.widget = None
如果setUp()成功,则无论runTest()
是否成功,都将运行tearDown()方法。
这样的测试代码工作环境称为* fixture *。
通常,许多小型测试用例将使用相同的夹具。在这种情况下,我们finally会将SimpleWidgetTestCase
子类化为许多小的一方法类,例如DefaultWidgetSizeTestCase
。这既耗时又令人沮丧,因此与 JUnit 一样,unittest提供了一种更简单的机制:
import unittest
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def tearDown(self):
self.widget.dispose()
self.widget = None
def test_default_size(self):
self.assertEqual(self.widget.size(), (50,50),
'incorrect default size')
def test_resize(self):
self.widget.resize(100,150)
self.assertEqual(self.widget.size(), (100,150),
'wrong size after resize')
这里我们没有提供runTest()
方法,而是提供了两种不同的测试方法。现在,每个类实例都将运行test_*()
方法之一,并为每个实例分别创建和销毁self.widget
。创建实例时,必须指定要运行的测试方法。为此,我们在构造函数中传递方法名称:
defaultSizeTestCase = WidgetTestCase('test_default_size')
resizeTestCase = WidgetTestCase('test_resize')
测试用例实例根据它们测试的Function分组在一起。 unittest为此提供了一种机制:* test suite *,由unittest的TestSuite类表示:
widgetTestSuite = unittest.TestSuite()
widgetTestSuite.addTest(WidgetTestCase('test_default_size'))
widgetTestSuite.addTest(WidgetTestCase('test_resize'))
为了使测试易于运行,我们将在后面看到,在每个测试模块中提供一个可调用的对象,该对象可返回预构建的测试套件,这是一个好主意:
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase('test_default_size'))
suite.addTest(WidgetTestCase('test_resize'))
return suite
or even:
def suite():
tests = ['test_default_size', 'test_resize']
return unittest.TestSuite(map(WidgetTestCase, tests))
由于创建带有许多类似命名的测试函数的TestCase子类是一种常见的模式,因此unittest提供了TestLoader的类,该类可用于自动化创建测试套件并将其填充到各个测试中的过程。例如,
suite = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)
将创建一个将运行WidgetTestCase.test_default_size()
和WidgetTestCase.test_resize
的测试套件。 TestLoader使用'test'
方法名称前缀来自动识别测试方法。
注意,各种测试用例的运行 Sequences 是pass根据字符串的内置 Sequences 对测试函数名称进行排序来确定的。
通常希望将测试用例套件组合在一起,以便一次为整个系统运行测试。这很容易,因为可以将TestSuite个实例添加到TestSuite就像将TestCase实例可以添加到TestSuite一样:
suite1 = module1.TheTestSuite()
suite2 = module2.TheTestSuite()
alltests = unittest.TestSuite([suite1, suite2])
您可以将测试用例和测试套件的定义与它们要测试的代码放在相同的模块中(例如widget.py
),但是将测试代码放在单独的模块中有很多优点,例如test_widget.py
:
-
可以从命令行独立运行测试模块。
-
测试代码可以更容易地与出厂代码分开。
-
在没有充分理由的情况下,很少有更改测试代码以使其适合测试代码的诱惑。
-
测试代码的修改频率应低于其测试代码。
-
经过测试的代码可以更容易地重构。
-
无论如何,用 C 编写的模块的测试都必须在单独的模块中,所以为什么不一致?
-
如果测试策略发生变化,则无需更改源代码。
25.3.5. 重用旧的测试代码
一些用户会发现他们已有想要从unittest运行的测试代码,而没有将每个旧的测试函数都转换为TestCase子类。
因此,unittest提供了FunctionTestCase类。 TestCase的此子类可用于包装现有的测试Function。还可以提供设置和拆卸Function。
给定以下测试Function:
def testSomething():
something = makeSomething()
assert something.name is not None
# ...
可以创建一个等效的测试用例实例,如下所示:
testcase = unittest.FunctionTestCase(testSomething)
如果在测试用例的操作中需要调用其他设置和拆卸方法,则也可以这样提供它们:
testcase = unittest.FunctionTestCase(testSomething,
setUp=makeSomethingDB,
tearDown=deleteSomethingDB)
为了简化现有测试套件的迁移,unittest支持提高AssertionError的测试以指示测试失败。但是,建议您改用显式的TestCase.fail*()
和TestCase.assert*()
方法,因为unittest的将来版本可能会区别AssertionError。
Note
即使可以使用FunctionTestCase将现有的测试库快速转换为基于unittest的系统,也不建议使用此方法。花时间设置适当的TestCase子类将使将来的测试重构变得更加轻松。
在某些情况下,现有测试可能是使用doctest模块编写的。如果是这样,doctest提供了一个DocTestSuite
类,该类可以根据现有基于doctest的测试自动构建unittest.TestSuite实例。
25.3.6. 跳过测试和预期的失败
2.7 版的新Function。
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")
pass制作一个在测试中希望跳过测试的调用skip()的装饰器,可以轻松滚动自己的跳过装饰器。除非传递的对象具有某个属性,否则此装饰器将跳过测试:
def skipUnlessHasattr(obj, attr):
if hasattr(obj, attr):
return lambda func: func
return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))
以下装饰器实现了测试跳过和预期的失败:
-
unittest.
skip
(原因)- 无条件跳过装饰测试。 原因应说明为何跳过测试。
-
unittest.
skipIf
(* condition , reason *)- 如果* condition *为 true,则跳过修饰的测试。
-
unittest.
skipUnless
(* condition , reason *)- 除非* condition *为 true,否则跳过装饰性测试。
-
unittest.
expectedFailure
( )- 将测试标记为预期的失败。如果测试在运行时失败,则该测试不算作失败。
-
exception
unittest.
SkipTest
(原因)- 引发此异常以跳过测试。
通常,您可以使用TestCase.skipTest()或跳过的装饰器之一,而不是直接提高它。
跳过的测试不会在它们周围运行setUp()
或tearDown()
。跳过的类不会运行setUpClass()
或tearDownClass()
。
25.3.7. 类和Function
本节深入介绍unittest的 API。
25.3.7.1. 测试用例
-
- class *
unittest.
TestCase
(* methodName ='runTest'*)
- class *
TestCase的每个实例将运行一个测试方法:名为* methodName *的方法。如果您还记得的话,我们有一个较早的示例,其内容如下:
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase('test_default_size'))
suite.addTest(WidgetTestCase('test_resize'))
return suite
在这里,我们创建WidgetTestCase
的两个实例,每个实例都运行一个测试。
- methodName *默认为
runTest()
。
TestCase实例提供三组方法:一组用于运行测试,另一组由测试实现用于检查条件和报告故障,还有一些查询方法允许收集有关测试本身的信息。
第一组(运行测试)的方法是:
-
setUp
( )- 调用准备测试夹具的方法。在调用测试方法之前立即调用该方法。除了AssertionError或SkipTest之外,此方法引发的任何异常都将被视为错误而不是测试失败。默认实现不执行任何操作。
-
tearDown
( )- 调用测试方法并记录结果后立即调用的方法。即使测试方法引发异常,也会调用此方法,因此子类中的实现在检查内部状态时可能需要格外小心。除AssertionError或SkipTest之外,此方法引发的任何异常都将被视为附加错误,而不是测试失败(因此会增加报告的错误总数)。无论setUp()成功如何,都将调用此方法,而不管测试方法的结果如何。默认实现不执行任何操作。
-
setUpClass
( )- 在运行单个类中的测试之前调用的类方法。调用
setUpClass
时以类作为唯一参数,并且必须将其修饰为classmethod():
- 在运行单个类中的测试之前调用的类方法。调用
@classmethod
def setUpClass(cls):
...
有关更多详细信息,请参见类和模块夹具。
2.7 版的新Function。
tearDownClass
( )- 在单个类中的测试运行后调用的类方法。调用
tearDownClass
时以类作为唯一参数,并且必须将其修饰为classmethod():
- 在单个类中的测试运行后调用的类方法。调用
@classmethod
def tearDownClass(cls):
...
有关更多详细信息,请参见类和模块夹具。
2.7 版的新Function。
run
(* result = None *)- 运行测试,将结果收集到作为* result 传递的测试结果对象中。如果Ellipsis result *或
None
,则会创建临时结果对象(pass调用defaultTestResult()方法)并使用。结果对象不会返回给run()的调用方。
- 运行测试,将结果收集到作为* result 传递的测试结果对象中。如果Ellipsis result *或
只需调用TestCase实例,就可以达到相同的效果。
skipTest
(原因)- 在测试方法期间调用此方法或setUp()会跳过当前测试。有关更多信息,请参见跳过测试和预期的失败。
2.7 版的新Function。
debug
( )- 运行测试而不收集结果。这样可以将测试引发的异常传播到调用方,并可以用来支持在调试器下运行测试。
TestCase类提供了几种 assert 方法来检查和报告故障。下表列出了最常用的方法(有关更多 assert 方法,请参见下表):
Method | Checks that | New in |
---|---|---|
assertEqual(a, b) | a == b | |
assertNotEqual(a, b) | a != b | |
assertTrue(x) | bool(x) is True | |
assertFalse(x) | bool(x) is False | |
assertIs(a, b) | a is b | 2.7 |
assertIsNot(a, b) | a is not b | 2.7 |
assertIsNone(x) | x is None | 2.7 |
assertIsNotNone(x) | x is not None | 2.7 |
assertIn(a, b) | a in b | 2.7 |
assertNotIn(a, b) | a not in b | 2.7 |
assertIsInstance(a, b) | isinstance(a, b) | 2.7 |
assertNotIsInstance(a, b) | not isinstance(a, b) | 2.7 |
所有 assert 方法(除了assertRaises(),assertRaisesRegexp()除外)都接受一个* msg *参数,如果指定该参数,该参数将用作失败时的错误消息(另请参见longMessage)。
assertEqual
(* first , second , msg = None *)- 测试* first 和 second *是否相等。如果值比较不相等,则测试将失败。
另外,如果* first 和 second *是完全相同的类型,并且是 list,tuple,dict,set,frozenset 或 unicode 或子类向addTypeEqualityFunc()注册的任何类型之一,则将按 Sequences 调用特定于类型的相等函数生成更有用的默认错误消息(另请参见类型专用方法列表)。
在 2.7 版中进行了更改:添加了自动调用特定于类型的相等函数的Function。
-
assertNotEqual
(* first , second , msg = None *)- 测试* first 和 second *不相等。如果这些值确实比较相等,则测试将失败。
-
assertTrue
(* expr , msg = None *)assertFalse
(* expr , msg = None *)- 测试* expr *是否为 true(或 false)。
请注意,这等效于bool(expr) is True
而不是expr is True
(后者使用assertIs(expr, True)
)。当有更多特定方法可用时(例如assertEqual(a, b)
而不是assertTrue(a == b)
),也应避免使用此方法,因为在发生故障的情况下,它们可以提供更好的错误消息。
assertIs
(* first , second , msg = None *)assertIsNot
(* first , second , msg = None *)- 测试* first 和 second *对同Pair象求值(或不求值)。
2.7 版的新Function。
assertIsNone
(* expr , msg = None *)assertIsNotNone
(* expr , msg = None *)- 测试* expr *是(或不是)
None
。
- 测试* expr *是(或不是)
2.7 版的新Function。
assertIn
(* first , second , msg = None *)assertNotIn
(* first , second , msg = None *)- 测试* first 在 second *中是(或不是)。
2.7 版的新Function。
assertIsInstance
(* obj , cls , msg = None *)assertNotIsInstance
(* obj , cls , msg = None *)- 测试* obj 是(或不是) cls *的实例(可以是isinstance()支持的类或类的 Tuples)。要检查确切的类型,请使用assertIs(type(obj), cls)。
2.7 版的新Function。
也可以使用以下方法检查是否引发了异常和警告:
Method | Checks that | New in |
---|---|---|
assertRaises(exc,fun,* args,** kwds) | fun(*args, **kwds) 加注* exc * | |
assertRaisesRegexp(exc,r,fun,* args,** kwds) | fun(*args, **kwds) 引发* exc ,并且消息与正则表达式 r *匹配 | 2.7 |
assertRaises
((* exception , callable *, *args , * kwds *)-
assertRaises
(* exception *)- 测试是否使用也传递给assertRaises()的任何位置或关键字参数调用* callable 时引发了异常。如果引发 exception ,则测试pass;如果引发另一个异常,则测试pass;如果未引发异常,则测试pass。为了捕获一组异常中的任何一个,包含异常类的 Tuples 可以作为 exception *传递。
-
如果仅给出* exception *参数,则返回一个上下文 Management 器,以便可以将内嵌代码而不是作为函数编写被测代码:
with self.assertRaises(SomeException):
do_something()
上下文 Management 器会将捕获的异常对象存储在其exception
属性中。如果要对引发的异常执行其他检查,这将很有用:
with self.assertRaises(SomeException) as cm:
do_something()
the_exception = cm.exception
self.assertEqual(the_exception.error_code, 3)
在 2.7 版中进行了更改:添加了使用assertRaises()作为上下文 Management 器的Function。
assertRaisesRegexp
((* exception , regexp , callable *, *args , * kwds *)-
assertRaisesRegexp
(* except , regexp *)- 像assertRaises()一样,还测试* regexp *是否与引发的异常的字符串表示形式匹配。 * regexp *可以是正则表达式对象,也可以是包含适合re.search()使用的正则表达式的字符串。例子:
-
self.assertRaisesRegexp(ValueError, "invalid literal for.*XYZ'$",
int, 'XYZ')
or:
with self.assertRaisesRegexp(ValueError, 'literal'):
int('XYZ')
2.7 版的新Function。
还有其他用于执行更具体检查的方法,例如:
Method | Checks that | New in |
---|---|---|
assertAlmostEqual(a, b) | round(a-b, 7) == 0 | |
assertNotAlmostEqual(a, b) | round(a-b, 7) != 0 | |
assertGreater(a, b) | a > b | 2.7 |
assertGreaterEqual(a, b) | a >= b | 2.7 |
assertLess(a, b) | a < b | 2.7 |
assertLessEqual(a, b) | a <= b | 2.7 |
assertRegexpMatches(s, r) | r.search(s) | 2.7 |
assertNotRegexpMatches(s, r) | not r.search(s) | 2.7 |
assertItemsEqual(a, b) | sorted(a)== sorted(b)并与不可哈希的 objs 一起使用 | 2.7 |
assertDictContainsSubset(a, b) | * a 中的所有键/值对都存在于 b *中 | 2.7 |
assertAlmostEqual
((* first , second , places = 7 , msg = None , delta = None *)assertNotAlmostEqual
((* first , second , places = 7 , msg = None , delta = None *)- pass计算差值,四舍五入到给定的小数位数* places (默认为 7),然后比较零,来测试 first 和 second 近似(或不近似)相等。请注意,这些方法将值四舍五入为小数位数的给定数量(即类似于round()函数),而不是有效位数*。
如果提供了* delta 而不是 places ,那么 first 和 second 之间的差值必须小于或等于(或大于) delta *。
同时提供* delta 和 places *会引发TypeError
。
在 2.7 版中进行了更改: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"
2.7 版的新Function。
assertRegexpMatches
(* text , regexp , msg = None *)- 测试* regexp 搜索是否匹配 text 。如果失败,错误消息将包含模式和 text (或模式和 text *意外匹配的部分)。 * regexp *可以是正则表达式对象,也可以是包含适合re.search()使用的正则表达式的字符串。
2.7 版的新Function。
assertNotRegexpMatches
(* text , regexp , msg = None *)- 验证* regexp 搜索与 text 不匹配。失败,并显示错误消息,包括模式和匹配的 text *部分。 * regexp *可以是正则表达式对象,也可以是包含适合re.search()使用的正则表达式的字符串。
2.7 版的新Function。
assertItemsEqual
((实际*,预期,* msg =无*)- 测试序列* expected 包含与 actual *相同的元素,而不管其 Sequences 如何。否则,将生成一条错误消息,列出序列之间的差异。
比较* acting 和 expected *时,*不可忽略重复的元素。它验证两个序列中每个元素的计数是否相同。它等效于assertEqual(sorted(expected), sorted(actual))
,但也适用于不可哈希对象序列。
在 Python 3 中,此方法名为assertCountEqual
。
2.7 版的新Function。
assertDictContainsSubset
(* expected , actual , msg = None *)- 测试字典* actual 中的键/值对是否是 expected *中的键/值对的超集。如果不是,则会生成一条错误消息,列出缺少的键和不匹配的值。
2.7 版的新Function。
从 3.2 版开始不推荐使用。
assertEqual()方法将相同类型对象的相等性检查分派给不同类型特定的方法。这些方法已经为大多数内置类型实现,但是也可以使用addTypeEqualityFunc()注册新方法:
addTypeEqualityFunc
(* typeobj , function *)- 注册由assertEqual()调用的特定于类型的方法,以检查两个完全相同的* typeobj *(不是子类)的对象是否相等。Function必须接受两个位置参数,第三个 msg = None 关键字参数,就像assertEqual()一样。当检测到前两个参数之间的不平等时,它必须提高self.failureException(msg) -可能提供有用的信息并在错误消息中详细说明不平等。
2.7 版的新Function。
下表总结了assertEqual()自动使用的特定于类型的方法的列表。请注意,通常不必直接调用这些方法。
Method | 用于比较 | New in |
---|---|---|
assertMultiLineEqual(a, b) | strings | 2.7 |
assertSequenceEqual(a, b) | sequences | 2.7 |
assertListEqual(a, b) | lists | 2.7 |
assertTupleEqual(a, b) | tuples | 2.7 |
assertSetEqual(a, b) | 集或冻结集 | 2.7 |
assertDictEqual(a, b) | dicts | 2.7 |
assertMultiLineEqual
(* first , second , msg = None *)- 测试多行字符串* first 等于字符串 second *。当不相等时,突出显示差异的两个字符串的差异将包含在错误消息中。在将 Unicode 字符串与assertEqual()进行比较时,默认使用此方法。
2.7 版的新Function。
assertSequenceEqual
(* seq1 , seq2 , msg = None , seq_type = None *)- 测试两个序列是否相等。如果提供了* seq_type ,则 seq1 和 seq2 都必须是 seq_type *的实例,否则将引发故障。如果 Sequences 不同,则会生成一条错误消息,显示两者之间的差异。
assertEqual()不会直接调用此方法,但是它用于实现assertListEqual()和assertTupleEqual()。
2.7 版的新Function。
assertListEqual
(* list1 , list2 , msg = None *)assertTupleEqual
(* tuple1 , tuple2 , msg = None *)- 测试两个列表或 Tuples 是否相等。如果不是,则构造一条错误消息,仅显示两者之间的差异。如果任何一个参数的类型错误,也会引发错误。将列表或 Tuples 与assertEqual()进行比较时,默认使用这些方法。
2.7 版的新Function。
assertSetEqual
(* set1 , set2 , msg = None *)- 测试两组是否相等。如果不是,则构造一条错误消息,列出这些组之间的差异。将集或冻结集与assertEqual()进行比较时,默认使用此方法。
如果* set1 或 set2 *中的任何一个都不具有set.difference()
方法,则失败。
2.7 版的新Function。
assertDictEqual
(* expected , actual , msg = None *)- 测试两个字典是否相等。如果不是,则构造一条错误消息,显示字典中的差异。默认情况下,将使用此方法比较对assertEqual()的调用中的字典。
2.7 版的新Function。
最后,TestCase提供以下方法和属性:
-
fail
(* msg = None *)- 无条件地表示测试失败,错误消息带有* msg *或
None
。
- 无条件地表示测试失败,错误消息带有* msg *或
-
failureException
- 此类属性给出了 test 方法引发的异常。如果测试框架需要使用特殊的异常(可能带有其他信息),则它必须将此异常子类化,以便与框架“公平竞争”。此属性的初始值为AssertionError。
-
longMessage
- 如果设置为
True
,则您传递给assert methods的任何明确的失败消息都将附加到正常失败消息的末尾。普通消息包含有关所涉及对象的有用信息,例如 assertEqual 的消息向您显示了两个不相等对象的代表。将此属性设置为True
可以使您获得除常规错误消息之外的自定义错误消息。
- 如果设置为
此属性默认为False
,这意味着传递到 assert 方法的自定义消息将使普通消息静音。
pass在调用 assert 方法之前将实例属性分配给True
或False
,可以在各个测试中覆盖类设置。
2.7 版的新Function。
maxDiff
- 此属性控制pass报告失败时的差异的 assert 方法来控制差异输出的最大长度。默认为 80 * 8 个字符。受此属性影响的 assert 方法是assertSequenceEqual()(包括委派给它的所有序列比较方法),assertDictEqual()和assertMultiLineEqual()。
将maxDiff
设置为None
表示没有最大的差异长度。
2.7 版的新Function。
测试框架可以使用以下方法来收集有关测试的信息:
-
countTestCases
( )- 返回此测试对象表示的测试数。对于TestCase个实例,它将始终为
1
。
- 返回此测试对象表示的测试数。对于TestCase个实例,它将始终为
-
defaultTestResult
( )- 返回应用于此测试用例类的测试结果类的实例(如果未向run()方法提供其他结果实例)。
对于TestCase实例,它将始终是TestResult的实例; TestCase的子类应在必要时覆盖此子类。
-
id
( )- 返回标识特定测试用例的字符串。这通常是测试方法的全名,包括模块和类名。
-
shortDescription
( )- 返回测试的描述,如果未提供描述,则返回
None
。此方法的默认实现返回测试方法的文档字符串的第一行(如果有)或None。
- 返回测试的描述,如果未提供描述,则返回
-
addCleanup
((* function *, *args , * kwargs *)- 在tearDown()之后添加一个要调用的函数,以清理测试期间使用的资源。将以与添加Function相反的 Sequences 调用这些Function(LIFO)。添加它们时,将使用传递到addCleanup()的任何参数和关键字参数来调用它们。
如果setUp()失败,即未调用tearDown(),则仍将调用添加的任何清除函数。
2.7 版的新Function。
doCleanups
( )- 如果setUp()引发异常,则在tearDown()之后或setUp()之后无条件调用此方法。
它负责调用addCleanup()添加的所有清除Function。如果您需要在tearDown()之前将清理Function称为* prior *,则可以自己调用doCleanups()。
doCleanups()一次将一种方法从清除函数堆栈中弹出,因此可以随时调用它。
2.7 版的新Function。
-
- class *
unittest.
FunctionTestCase
(* testFunc , setUp = None , tearDown = None , description = None *)
- class *
25.3.7.1.1. 弃用的别名
由于历史原因,某些TestCase方法具有一个或多个别名,现在不建议使用。下表列出了正确的名称及其不赞成使用的别名:
Note
Method Name | Deprecated alias(es) |
---|---|
assertEqual() | failUnlessEqual, assertEquals |
assertNotEqual() | failIfEqual |
assertTrue() | failUnless, assert_ |
assertFalse() | failIf |
assertRaises() | failUnlessRaises |
assertAlmostEqual() | failUnlessAlmostEqual |
assertNotAlmostEqual() | failIfAlmostEqual |
从 2.7 版开始不推荐使用:第二列中列出的别名
25.3.7.2. 分组测试
- 类别
unittest.
TestSuite
(测试=())- 此类表示各个测试用例和测试套件的集合。该类提供测试运行程序所需的接口,以使其能够像其他任何测试用例一样运行。运行TestSuite实例与遍历套件(分别运行每个测试)相同。
如果给出* tests *,则它必须是单个测试用例或其他最初用于构建套件的测试套件的可迭代项。稍后提供了其他方法来将测试用例和套件添加到集合中。
TestSuite对象的行为与TestCase对象非常相似,不同之处在于它们实际上并未实施测试。相反,它们用于将测试聚合到应一起运行的测试组中。可以使用一些其他方法将测试添加到TestSuite实例:
这等效于迭代* tests *,对每个元素调用addTest()。
-
run
(结果)- 运行与此套件相关的测试,将结果收集到作为* result *传递的测试结果对象中。请注意,与TestCase.run()不同,TestSuite.run()要求传入结果对象。
-
debug
( )- 运行与此套件相关的测试,而不收集结果。这允许将测试引发的异常传播到调用方,并可用于支持在调试器下运行测试。
-
countTestCases
( )- 返回此测试对象表示的测试数量,包括所有单个测试和子套件。
-
__iter__
( )
在 2.7 版中进行了更改:在早期版本中,TestSuite直接访问测试而不是pass迭代访问测试,因此,覆盖iter()不足以提供测试。
在TestSuite对象的典型用法中,run()方法是由TestRunner
而不是finally用户测试工具调用的。
25.3.7.3. 加载和运行测试
- 类别
unittest.
TestLoader
- TestLoader类用于从类和模块创建测试套件。通常,不需要创建此类的实例。 unittest模块提供了可以与unittest.defaultTestLoader共享的实例。但是,使用子类或实例可以自定义一些可配置的属性。
TestLoader对象具有以下方法:
-
loadTestsFromTestCase
(* testCaseClass *)- 返回TestCase派生的
testCaseClass
中包含的所有测试用例的套件。
- 返回TestCase派生的
-
loadTestsFromModule
(* module *)- 返回给定模块中包含的所有测试用例的套件。此方法在* module *中搜索从TestCase派生的类,并为为该类定义的每个测试方法创建该类的实例。
Note
虽然使用TestCase派生的类的层次结构可以方便地共享固定装置和辅助函数,但是在不打算直接实例化的 Base Class 上定义测试方法在此方法中不能很好地发挥作用。但是,当固定装置不同且在子类中定义时,这样做可能会很有用。
如果模块提供load_tests
函数,则将调用它以加载测试。这允许模块自定义测试加载。这是load_tests protocol。
在 2.7 版中进行了更改:添加了对load_tests
的支持。
loadTestsFromName
(* name , module = None *)- 给定字符串说明符,返回所有测试用例的套件。
说明符* name *是一个“点名”,可以解析为模块,测试用例类,测试用例类中的测试方法,TestSuite实例或返回TestCase或TestSuite实例的可调用对象。这些检查按照此处列出的 Sequences 进行;也就是说,可能的测试用例类上的方法将被选择为“测试用例类内的测试方法”,而不是“可调用对象”。
例如,如果您有一个包含TestCase派生类SampleTestCase
的模块SampleTests
以及三个测试方法(test_one()
,test_two()
和test_three()
),则说明符'SampleTests.SampleTestCase'
将导致此方法返回将运行所有三个测试方法的套件。使用说明符'SampleTests.SampleTestCase.test_two'
将导致它返回仅运行test_two()
测试方法的测试套件。该说明符可以引用尚未导入的模块和包。它们将作为副作用导入。
该方法可选地相对于给定的* module 解析 name *。
-
loadTestsFromNames
(* names , module = None *)- 与loadTestsFromName()相似,但采用名称序列而不是单个名称。返回值是一个测试套件,它支持为每个名称定义的所有测试。
-
getTestCaseNames
(* testCaseClass *)- 返回在* testCaseClass *中找到的方法名称的排序序列;这应该是TestCase的子类。
-
discover
(* start_dir , pattern ='test * .py', top_level_dir = None *)- pass从指定的开始目录递归到子目录中,找到所有测试模块,然后返回包含它们的 TestSuite 对象。仅加载与* pattern *匹配的测试文件。 (使用 Shell 样式模式匹配.)仅加载可导入的模块名称(即有效的 Python 标识符)。
所有测试模块必须可从项目的顶层导入。如果起始目录不是顶级目录,则必须单独指定顶级目录。
如果导入模块失败,例如由于语法错误,则将其记录为单个错误,并且发现将 continue。
如果测试软件包名称(带有_的目录)与该模式匹配,则将检查该软件包的load_tests
函数。如果存在,则将使用* loader , tests , pattern *进行调用。
如果存在 load_tests,则发现不会不递归到软件包中,load_tests
负责加载软件包中的所有测试。
故意不将模式存储为 loader 属性,以便程序包可以自己 continue 发现。 * top_level_dir *已存储,因此load_tests
无需将此参数传递给loader.discover()
。
- start_dir *可以是点分模块名称以及目录。
2.7 版的新Function。
TestLoader的以下属性可以pass子类化或在实例上分配来配置:
testMethodPrefix
- 字符串,提供方法名称的前缀,该名称将被解释为测试方法。默认值为
'test'
。
- 字符串,提供方法名称的前缀,该名称将被解释为测试方法。默认值为
这会影响getTestCaseNames()和所有loadTestsFrom*()
方法。
-
sortTestMethodsUsing
- 在getTestCaseNames()和所有
loadTestsFrom*()
方法中对方法名称进行排序时用于比较方法名称的函数。默认值为内置cmp()函数;该属性也可以设置为None以禁用排序。
- 在getTestCaseNames()和所有
-
suiteClass
- 从测试列表构造测试套件的可调用对象。在结果对象上不需要任何方法。默认值为TestSuite类。
这会影响所有loadTestsFrom*()
方法。
- 类别
unittest.
TestResult
- 此类用于编译有关哪些测试成功和失败的信息。
TestResult对象存储一组测试的结果。 TestCase和TestSuite类可确保正确记录结果;测试作者无需担心记录测试结果。
构建在unittest之上的测试框架可能希望访问pass运行一组测试生成的TestResult对象以进行报告。为此,TestRunner.run()
方法返回一个TestResult实例。
TestResult实例具有以下属性,这些属性在检查运行一组测试的结果时会引起关注:
errors
- 包含 2 个 Tuples 的TestCase实例和包含格式化回溯的字符串的列表。每个 Tuples 代表一个引发意外异常的测试。
在版本 2.2 中进行了更改:包含格式化的回溯,而不是sys.exc_info()个结果。
failures
- 包含 2 个 Tuples 的TestCase实例和包含格式化回溯的字符串的列表。每个 Tuples 代表一个测试,在该测试中使用
TestCase.assert*()
方法明确指示了失败。
- 包含 2 个 Tuples 的TestCase实例和包含格式化回溯的字符串的列表。每个 Tuples 代表一个测试,在该测试中使用
在版本 2.2 中进行了更改:包含格式化的回溯,而不是sys.exc_info()个结果。
skipped
- 包含 2 个 Tuples 的TestCase实例和字符串的列表,其中包含跳过测试的原因。
2.7 版的新Function。
-
expectedFailures
- 包含 2 个 Tuples 的TestCase实例和包含格式化回溯的字符串的列表。每个 Tuples 代表测试用例的预期失败。
-
unexpectedSuccesses
- 包含TestCase个实例的列表,这些实例被标记为预期失败,但已成功。
-
shouldStop
- 当测试执行应在stop()停止时设置为
True
。
- 当测试执行应在stop()停止时设置为
-
testsRun
- 到目前为止,测试总数。
-
buffer
- 如果设置为 true,则
sys.stdout
和sys.stderr
将被缓冲在被调用的startTest()和stopTest()之间。如果测试失败或错误,则仅将收集的输出回显到实际的sys.stdout
和sys.stderr
上。任何输出也将附加到失败/错误消息。
- 如果设置为 true,则
2.7 版的新Function。
failfast
- 如果设置为 true,则在第一次失败或错误时会调用stop(),从而暂停测试运行。
2.7 版的新Function。
-
wasSuccessful
( )- 如果到目前为止运行的所有测试均已pass,则返回
True
,否则返回False
。
- 如果到目前为止运行的所有测试均已pass,则返回
-
stop
( )- pass将shouldStop属性设置为
True
,可以调用此方法来表明正在运行的测试集应中止。TestRunner
对象应遵守此标志并在不运行任何其他测试的情况下返回。
- pass将shouldStop属性设置为
例如,当用户从键盘发出break signal 时,TextTestRunner类将使用此Function来停止测试框架。提供TestRunner
实现的交互式工具可以类似的方式使用它。
TestResult类的以下方法用于维护内部数据结构,并且可以在子类中扩展以支持其他报告要求。这对于在运行测试时支持交互式报告的构建工具特别有用。
-
startTest
(测试)- 在将要运行测试用例* test *时调用。
-
stopTest
(测试)- 在测试用例* test *执行完毕后调用,无论结果如何。
-
startTestRun
( )- 在执行任何测试之前调用一次。
2.7 版的新Function。
stopTestRun
( )- 执行完所有测试后调用一次。
2.7 版的新Function。
addError
(* test , err *)- 当测试用例* test *引发意外异常时调用。 * err *是sys.exc_info():
(type, value, traceback)
返回的形式的 Tuples。
- 当测试用例* test *引发意外异常时调用。 * err *是sys.exc_info():
默认实现将 Tuples(test, formatted_err)
附加到实例的errors属性,其中* formatted_err 是从 err *派生的格式化回溯。
addFailure
(* test , err *)- 当测试用例* test *发出故障 signal 时调用。 * err *是sys.exc_info():
(type, value, traceback)
返回的形式的 Tuples。
- 当测试用例* test *发出故障 signal 时调用。 * err *是sys.exc_info():
默认实现将 Tuples(test, formatted_err)
附加到实例的failures属性,其中* formatted_err 是从 err *派生的格式化回溯。
addSuccess
(测试)- 在测试用例* test *成功时调用。
默认实现不执行任何操作。
addSkip
(* test , reason *)- 当测试用例* test *被跳过时调用。 原因是测试给出跳过的原因。
默认实现将 Tuples(test, reason)
附加到实例的skipped属性。
addExpectedFailure
(* test , err *)- 在测试用例* test *失败但被标记为expectedFailure()装饰器时调用。
默认实现将 Tuples(test, formatted_err)
附加到实例的expectedFailures属性,其中* formatted_err 是从 err *派生的格式化回溯。
addUnexpectedSuccess
(测试)- 当测试用例* test *用expectedFailure()装饰器标记但成功时调用。
默认实现将测试附加到实例的unexpectedSuccesses属性。
-
- class *
unittest.
TextTestResult
(* stream , descriptions , verbosity *)
- TextTestRunner使用的TestResult的具体实现。
- class *
2.7 版中的新Function:此类以前称为_TextTestResult
。旧名称仍然作为别名存在,但已过时。
-
unittest.
defaultTestLoader
- 打算共享的TestLoader类的实例。如果不需要自定义TestLoader,则可以使用此实例,而不必重复创建新实例。
-
- class *
unittest.
TextTestRunner
(* stream = sys.stderr , descriptions = True , verbosity = 1 , failfast = False , buffer = False , resultclass = None *)
- 一个基本的测试运行器实现,可以在标准错误上打印结果。它具有一些可配置的参数,但本质上非常简单。运行测试套件的图形应用程序应提供替代的实现。
- class *
-
_makeResult
( )- 此方法返回
run()
使用的TestResult
实例。它不打算直接调用,但是可以在子类中重写以提供自定义TestResult
。
- 此方法返回
_makeResult()
实例化TextTestRunner
构造函数中作为resultclass
参数传递的类或可调用对象。如果未提供resultclass
,则默认为TextTestResult。结果类使用以下参数实例化:
stream, descriptions, verbosity
unittest.
main
(([* module * [,* defaultTest * [,* argv * [,* testRunner * [,* testLoader * [,* exit * [,* verbosity * [,* failfast * [,* catchbreak * [,缓冲区]]]]]]]]]]]]))- 一个命令行程序,它从* module *加载一组测试并运行它们;这主要是为了使测试模块方便执行。此Function最简单的用法是在测试脚本的末尾包含以下行:
if __name__ == '__main__':
unittest.main()
您可以pass传入 verbosity 参数来运行包含更详细信息的测试:
if __name__ == '__main__':
unittest.main(verbosity=2)
如果没有pass* argv 指定测试名称,则 defaultTest 参数是要运行的测试的名称。如果未指定或None
并且没有pass argv 提供测试名称,则将运行 module *中找到的所有测试。
-
argv *参数可以是传递给程序的选项列表,第一个元素是程序名称。如果未指定或
None
,则使用sys.argv的值。 -
testRunner *参数可以是测试运行器类,也可以是已经创建的实例。默认情况下,
main
调用sys.exit()并带有退出代码,以指示测试运行成功或失败。 -
testLoader *参数必须是TestLoader实例,默认为defaultTestLoader。
main
支持pass传入参数exit=False
从交互式解释器中使用。这将在标准输出上显示结果,而无需调用sys.exit():
>>> from unittest import main
>>> main(module='test_module', exit=False)
- failfast , catchbreak 和 buffer *参数的作用与同名command-line options相同。
调用main
实际上会返回TestProgram
类的实例。这会将测试结果存储为result
属性。
在 2.7 版中进行了更改:添加了* exit , verbosity , failfast , catchbreak 和 buffer *参数。
25.3.7.3.1. load_tests 协议
2.7 版的新Function。
模块或软件包可以pass实现称为load_tests
的Function来自定义在正常测试运行或测试发现期间如何从中加载测试。
如果测试模块定义了load_tests
,它将由TestLoader.loadTestsFromModule()调用,并带有以下参数:
load_tests(loader, standard_tests, None)
它应该返回TestSuite。
- loader *是TestLoader进行加载的实例。 * standard_tests *是默认情况下将从模块中加载的测试。测试模块通常只想在标准测试集中添加或删除测试。当加载软件包作为测试发现的一部分时,将使用第三个参数。
从一组特定的TestCase类加载测试的典型load_tests
函数可能类似于:
test_cases = (TestCase1, TestCase2, TestCase3)
def load_tests(loader, tests, pattern):
suite = TestSuite()
for test_class in test_cases:
tests = loader.loadTestsFromTestCase(test_class)
suite.addTests(tests)
return suite
如果从命令行或pass调用TestLoader.discover()(使用与程序包名称匹配的模式)启动发现,则将在程序包__init__.py
中检查load_tests
。
Note
默认模式是'test*.py'
。这会匹配以'test'
开头但不会匹配任何测试目录的所有 Python 文件。
像'test*'
这样的模式将匹配测试包和模块。
如果程序包__init__.py
定义了load_tests
,则它将被调用,并且发现不会 continue 进入程序包。 load_tests
使用以下参数调用:
load_tests(loader, standard_tests, pattern)
这应该返回一个TestSuite,代表该程序包中的所有测试。 (standard_tests
仅包含从__init__.py
收集的测试.)
由于该模式已传递到load_tests
中,因此程序包可以自由 continue(并可能修改)测试发现。测试包的“不执行任何操作” load_tests
函数如下所示:
def load_tests(loader, standard_tests, pattern):
# top level directory cached on loader instance
this_dir = os.path.dirname(__file__)
package_tests = loader.discover(start_dir=this_dir, pattern=pattern)
standard_tests.addTests(package_tests)
return standard_tests
25.3.8. 类和模块夹具
类和模块级别的固定装置在TestSuite中实现。当测试套件遇到来自新类的测试时,则调用前一类的tearDownClass()
(如果有),然后调用新类的setUpClass()
。
同样,如果测试来自与先前测试不同的模块,则运行来自先前模块的tearDownModule
,然后运行来自新模块的setUpModule
。
完成所有测试后,将运行finally的tearDownClass
和tearDownModule
。
请注意,共享夹具不能与测试并行化等[潜在]Function配合使用,并且会破坏测试隔离。应该小心使用它们。
由 unittest 测试加载程序创建的测试的默认 Sequences 是将来自相同模块和类的所有测试组合在一起。这将导致每个类和模块一次调用setUpClass
/setUpModule
(等)。如果您将 Sequences 随机化,以使来自不同模块和类的测试彼此相邻,则可以在一次测试运行中多次调用这些共享的夹具Function。
共享夹具不适用于非标准 Order 的套件。 BaseTestSuite
对于不希望支持共享装置的框架仍然存在。
如果在共享夹具Function之一期间引发任何异常,则将测试报告为错误。因为没有相应的测试实例,所以创建了_ErrorHolder
对象(与TestCase具有相同的接口)来表示错误。如果您只是使用标准的单元测试测试运行程序,那么此细节并不重要,但是如果您是框架作者,则可能很重要。
25.3.8.1. setUpClass 和 tearDownClass
这些必须作为类方法实现:
import unittest
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls._connection = createExpensiveConnectionObject()
@classmethod
def tearDownClass(cls):
cls._connection.destroy()
如果要在 Base Class 上调用setUpClass
和tearDownClass
,则必须自己调用它们。 TestCase中的实现为空。
如果在setUpClass
期间引发异常,则不会运行该类中的测试,也不会运行tearDownClass
。跳过的类不会运行setUpClass
或tearDownClass
。如果该异常是SkipTest异常,则该类将被报告为已跳过而不是错误。
25.3.8.2. setUpModule 和 tearDownModule
这些应实现为Function:
def setUpModule():
createConnection()
def tearDownModule():
closeConnection()
如果setUpModule
中引发异常,则模块中的任何测试都不会运行,而tearDownModule
也不会运行。如果异常是SkipTest异常,则模块将被报告为已跳过而不是错误。
25.3.9. signal 处理
单元测试的-c/--catch命令行选项,以及unittest.main()的catchbreak
参数,在测试运行期间提供了对 Control-C 的更友好处理。启用捕获break行为后,control-C 将允许当前运行的测试完成,然后测试运行将结束并报告到目前为止的所有结果。第二个 Control-c 将以通常方式提高KeyboardInterrupt。
控件 c 处理 signal 处理程序try与安装自己的signal.SIGINT
处理程序的代码或测试保持兼容。如果调用unittest
处理程序但不是*已安装的signal.SIGINT
处理程序,即它已被测试系统替换并委托给它,则它将调用默认处理程序。pass替换已安装的处理程序并委托给它的代码,这通常是预期的行为。对于需要禁用unittest
control-c 处理的单个测试,可以使用removeHandler()装饰器。
有一些 Util Function可供框架作者使用,以在测试框架中启用 Control-C 处理Function。
unittest.
installHandler
( )- 安装 control-c 处理程序。当收到
signal.SIGINT
时(通常是响应用户按下 Ctrl-c),所有已注册的结果都被调用stop()。
- 安装 control-c 处理程序。当收到
2.7 版的新Function。
unittest.
registerResult
(结果)- 注册TestResult对象以进行 Control-C 处理。注册结果会对其存储一个弱引用,因此不会阻止结果被垃圾收集。
如果未启用 control-c 处理,则注册TestResult对象没有副作用,因此测试框架可以无条件地注册其创建的所有结果,而与是否启用处理无关。
2.7 版的新Function。
unittest.
removeResult
(结果)- 删除注册结果。删除结果后,将不再响应该 Control-c 在该结果对象上调用stop()。
2.7 版的新Function。
unittest.
removeHandler
(* function = None *)- 如果不带参数调用此函数,则会删除 Control-C 处理程序(如果已安装)。此函数还可以用作测试装饰器,以在执行测试时临时删除处理程序:
@unittest.removeHandler
def test_signal_handling(self):
...
2.7 版的新Function。