unittest
unittest - 单元测试框架
2.1版本中的新功能。
(如果您已经熟悉测试的基本概念,则可能需要跳至断言方法列表。)
Python单元测试框架有时被称为“PyUnit”,是由Kent Beck和Erich Gamma编写的JUnit的Python语言版本。而JUnit则是Kent的Smalltalk测试框架的Java版本。每种语言都是其各自语言的事实上的标准单元测试框架。
unittest
支持测试自动化,共享测试的设置和关闭代码,将测试集合到集合中,以及测试与报告框架无关。unittest
模块提供的类可以很容易地支持这些质量以进行一系列测试。
为了实现这一点,unittest
支持一些重要的概念:
测试夹具
测试夹具
代表执行一个或多个测试
所需的准备工作,以及任何关联的清理操作。例如,这可能涉及创建临时或代理数据库,目录或启动服务器进程。测试
caseA 测试用例
是测试
的最小单元。它检查对特定输入集的特定响应。unittest
提供了一个基类,TestCase
它可以用来创建新的测试用例
。测试套件测试套件
是测试用例
,测试
套件或两者的集合。它用于聚合应该一起执行的测试
。test runner 测试运行器
是协调测试
执行并将结果提供给用户的组件。跑步者可以使用图形界面,文本界面或返回特殊值来指示执行测试
的结果。
测试用例和测试夹具的概念通过TestCase
和FunctionTestCase
类来支持;前者应在创建新测试时使用,后者可在将现有测试代码与unittest
驱动框架集成时使用。当使用测试夹具时TestCase
,可以重写setUp()
和tearDown()
方法来为夹具提供初始化和清理。有了这些FunctionTestCase
,现有的函数可以传递给构造函数用于这些目的。当测试运行时,夹具初始化首先运行;如果成功,则在执行测试后运行清理方法,而不管测试结果如何。每个实例TestCase
仅用于运行单个测试方法,因此每个测试都会创建一个新的固件。
测试套件由TestSuite
课程实施。这个类允许汇总单独的测试和测试套件; 当套件执行时,所有直接添加到套件和“child”测试套件的测试都会运行。
测试运行器是提供单个方法的对象run()
,它接受一个TestCase
或一个TestSuite
对象作为参数,并返回一个结果对象。该类TestResult
被提供用作结果对象。unittest
提供了TextTestRunner
默认情况下在标准错误流上报告测试结果的测试运行器的示例。执行器可以被移植到其他环境(如图形环境),而不需要从特定的类派生。
另请参阅
Module
doctest
另一种测试支持模块具有非常不同的风味。unittest
2:针对Python 2.4-2.6的新单元测试功能的回溯 Python 2.7的单元测试中增加了许多新功能,其中包括测试发现。unittest
2允许您在早期版本的Python中使用这些功能。简单的Smalltalk测试:使用模式 Kent Beck关于使用共享模式测试框架的原始论文unittest
。 鼻子和py.test 第三方单元测试框架,用于编写测试的轻量级语法。例如,assert func(10) == 42
。Python测试工具分类标准Python测试工具的一个广泛列表,包括功能测试框架和模拟对象库。在Python邮件列表中进行测试在Python中讨论测试和测试工具的特殊兴趣小组。
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
相反的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
以上示例显示了最常用的unittest
功能,足以满足许多日常测试需求。文档的其余部分从最基本的原则中探索完整的功能集。
2.命令行界面
可以从命令行使用unittest模块来运行模块,类或甚至单个测试方法的测试:
python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
您可以使用模块名称和完全限定的类或方法名称的任意组合来传递列表。
您可以通过传入-v标志来运行更详细的测试(更高级的冗长):
python -m unittest -v test_module
有关所有命令行选项的列表:
python -m unittest -h
在版本2.7中更改:在早期版本中,只能运行单个测试方法,而不能运行模块或类。
2.1. 命令行选项
unittest
支持这些命令行选项:
-b, --buffer
标准输出和标准错误流在测试运行期间被缓冲。丢弃通过测试期间的输出。输出在测试失败或错误时正常回显并被添加到失败消息中。
-c, --catch
Control-C
在测试运行期间,等待当前测试结束,然后报告所有结果。第二个Control-C
提出了正常的KeyboardInterrupt
例外。
有关提供此功能的功能,请参阅信号处理。
-f, --failfast
停止第一次错误或失败的测试运行。
新的2.7版:命令行选项-b
,-c
并-f
添加。
命令行也可以用于测试发现,用于运行项目中的所有测试或者只是一个子集。
3.测试发现
2.7版本的新功能。
Unittest支持简单的测试发现。为了与测试发现兼容,所有的测试文件必须是模块或包从项目的顶层目录导入的(这意味着它们的文件名必须是有效的标识符)。
测试发现在中实现TestLoader.discover()
,但也可以从命令行使用。基本的命令行用法是:
cd project_directory
python -m unittest discover
discover
子命令有以下选项:
-v, --verbose
详细输出
-s, --start-directory directory
目录开始发现(.
默认)
-p, --pattern pattern
匹配测试文件的模式(test*.py
默认)
-t, --top-level-directory directory
项目的顶级目录(默认为开始目录)
-s
,-p
和-t
选项可以作为位置参数按顺序传递。以下两条命令行是等效的:
python -m unittest discover -s project_directory -p "*_test.py"
python -m unittest discover project_directory "*_test.py"
除了作为路径之外,还可以传递包名称myproject.subpackage.test
作为起始目录。随后将导入您提供的包名称,并将其在文件系统上的位置用作起始目录。
警告
测试发现通过导入它们来加载测试。一旦测试发现已经从您指定的开始目录中找到所有测试文件,它会将路径转换为要导入的软件包名称。例如foo/bar/baz.py
将被导入为foo.bar.baz
。
如果您有一个全局安装的软件包,并尝试在另一个软件包副本上进行测试发现,那么导入可能
发生在错误的地方。如果发生这种情况,测试发现会警告您并退出。
如果您将开始目录作为软件包名称而不是目录的路径提供,那么discover会假定从其导入的位置是您想要的位置,因此您将不会收到警告。
测试模块和软件包可以通过load_tests协议定制测试加载和发现。
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')
请注意,为了测试某些东西,我们使用基类assert*()
提供的方法之一TestCase
。如果测试失败
,将会引发异常,并将unittest
测试用例标识为失败
。任何其他异常将被视为错误
。这有助于识别问题所在:故障
是由不正确的结果引起的 - a 5您期望的a 6. 错误
是由不正确的代码引起的 - 例如,TypeError
由不正确的函数调用引起的错误
。
运行测试用例的方式将在后面介绍。现在,请注意为了构造这样一个测试用例的实例,我们调用它的构造函数而不带参数:
testCase = DefaultWidgetSizeTestCase()
现在,这样的测试案例可能很多,并且它们的设置可能是重复的。在上面的情况下,Widget
在每个100个Widget
测试用例子类中构造a 意味着难看的重复。
幸运的是,我们可以通过实现一个称为的方法来分解这些设置代码,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()
成功,tearDown()
方法将运行,无论runTest()
成功与否。
测试代码的这种工作环境称为夹具
。
通常,很多小型测试案例都会使用相同的夹具。在这种情况下,我们最终会将子类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')
测试用例实例根据它们测试的功能分组在一起。unittest
为此提供了一个机制:测试套件
,由下式表示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
甚至:
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'
方法名称前缀自动识别测试方法。
请注意,各种测试用例的运行顺序是通过对测试函数名称与字符串的内置排序进行排序来确定的。
通常希望将测试用例集合在一起,以便一次运行整个系统的测试。这很容易,因为TestSuite
可以将实例添加到a中TestSuite
,因为TestCase
实例可以添加到a TestSuite
:
suite1 = module1.TheTestSuite()
suite2 = module2.TheTestSuite()
alltests = unittest.TestSuite([suite1, suite2])
您可以将测试用例和测试套件的定义放置在与测试代码相同的模块中(例如widget.py
),但将测试代码放置在单独的模块中有几个优点,例如test_widget.py
:
- 测试模块可以从命令行单独运行。
- 测试代码可以更容易地从提供的代码中分离出来。
- 更改测试代码以适应其测试代码的诱惑没有很好的理由。
- 测试代码应该比它测试的代码更加频繁地被修改。
- 测试过的代码可以更容易地重构。
- 用C编写的模块测试必须在不同的模块中,为什么不一致呢?
- 如果测试策略发生变化,则不需要更改源代码。
5.重新使用旧的测试代码
有些用户会发现他们有现成的测试代码,他们想从中运行unittest
,而不是将每个旧的测试函数都转换为TestCase
子类。
出于这个原因,unittest
提供一个FunctionTestCase
类。这个子类TestCase
可以用来包装现有的测试函数。还可以提供设置和拆卸功能。
鉴于以下测试功能:
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
有所不同。
注意
尽管FunctionTestCase
可以用来将现有的测试库快速转换为unittest
基于系统,但不建议采用这种方法。花时间设置适当的TestCase
子类将使未来的测试重构变得更容易。
在某些情况下,现有的测试可能是使用该doctest
模块编写的。如果是这样,doctest
提供一个DocTestSuite
可以unittest.TestSuite
从现有doctest
测试中自动构建实例的类。
6.跳过测试和预期的失败
2.7版本的新功能。
Unittest支持跳过单独的测试方法甚至整个测试类。此外,它支持将测试标记为“预期失败”,这是一种被破坏并将失败的测试,但不应被视为失败TestResult
。
跳过测试只是使用skip()
装饰器或其一个条件变体的问题。
基本跳过看起来像这样:
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)
无条件地跳过装饰测试。理由
应该描述为什么测试被跳过。
unittest.skipIf(condition, reason)
如果条件
为真,跳过装饰测试。
unittest.skipUnless(condition, reason)
除非条件
为真,否则跳过装饰测试。
unittest.expectedFailure()
将测试标记为预期的失败。如果运行时测试失败,测试不算作失败。
exception unittest.SkipTest(reason)
这个例外引起了跳过测试。
通常你可以使用TestCase.skipTest()
或者跳过一个装饰器,而不是直接引用。
跳过的测试不会有setUp()
或tearDown()
绕过它们。被跳过的类不会有setUpClass()
或tearDownClass()
运行。
7.类和功能
本节将深入介绍API unittest
。
7.1. 测试用例
class unittest.TestCase(methodName='runTest')
TestCase
该类的实例代表unittest
宇宙中最小的可测试单元。此类旨在用作基类,具体测试由具体的子类实现。该类实现了测试运行器所需的接口,以允许它驱动测试,以及测试代码可用于检查和报告各种故障的方法。
每个实例都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):
...
有关更多详细信息,请参阅Class和Module Fixtures。
2.7版本的新功能。
tearDownClass()
在单个类中的测试之后调用的类方法已经运行。tearDownClass
被称为类作为唯一的参数,并且必须被修饰为classmethod()
:
@classmethod
def tearDownClass(cls):
...
有关更多详细信息,请参阅Class和Module Fixtures。
2.7版本的新功能。
run(result=None)
运行测试,将结果
收集到作为结果
传递的测试结果
对象中。如果省略结果
或None
创建临时结果
对象(通过调用defaultTestResult()
方法)并使用。结果
对象不会返回给run()
调用者。
简单地调用TestCase
实例可能会产生同样的效果。
skipTest(reason)
在测试方法中调用它或setUp()
跳过当前测试。有关更多信息,请参阅跳过测试和预期故障。
2.7版本的新功能。
debug()
运行测试而不收集结果。这允许将测试引发的异常传播给调用者,并且可以用来支持在调试器下运行测试。
本TestCase
类提供了一些断言方法来检查并报告故障。下表列出了最常用的方法(有关更多断言方法,请参阅下表):
方法 | 检查 | 新的 |
---|---|---|
assertEqual(a,b) | a == b | |
assertNotEqual(a,b) | a!= b | |
assertTrue(x)的 | bool(x)为真 | |
assertFalse(x)的 | bool(x)是False | |
assertIs(a,b) | a是b | 2.7 |
assertIsNot(a,b) | a不是b | 2.7 |
assertIsNone(x)的 | x是无 | 2.7 |
assertIsNotNone(x)的 | x不是无 | 2.7 |
assertIn(a,b) | 一个在b | 2.7 |
assertNotIn(a,b) | 一个不在b | 2.7 |
assertIsInstance(a,b) | isinstance(a,b) | 2.7 |
assertNotIsInstance(a,b) | 不是isinstance(a,b) | 2.7 |
所有的断言方法(除了assertRaises()
,assertRaisesRegexp()
)接受一个msg
参数,如果指定的话,它被用作失败时的错误消息(另请参见longMessage
)。
assertEqual(first, second, msg=None)
测试第一
和第二
是相等的。如果这些值不相等,则测试将失败。
另外,如果第一个
和第二个
类型完全相同,并且列表,元组,dict,set,frozenset或unicode中的一个是完全相同的类型,或者addTypeEqualityFunc()
将调用子类与类型特定的相等函数一起注册的任何类型,以便生成更有用的默认错误信息(另请参阅特定于类型的方法列表)。
在版本2.7中更改:添加了特定于类型的相等函数的自动调用。
assertNotEqual(first, second, msg=None)
测试第一
和第二
不相等。如果这些值确实相等,则测试将失败。
assertTrue(expr, msg=None)assertFalse(expr, msg=None)
测试expr
是否为真(或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)
测试第一个
和第二个
评估(或不评估)到同一个对象。
2.7版本的新功能。
assertIsNone(expr, msg=None)assertIsNotNone(expr, msg=None)
测试expr
是否(或不)None
。
2.7版本的新功能。
assertIn(first, second, msg=None)assertNotIn(first, second, msg=None)
首先
测试(或不)在第二
。
2.7版本的新功能。
assertIsInstance(obj, cls, msg=None)assertNotIsInstance(obj, cls, msg=None)
测试obj
是否(或不是)cls的
一个实例(可以是一个类或一个类的元组,可以支持isinstance()
)。要检查确切的类型,请使用assertIs(type(obj), cls)
。
2.7版本的新功能。
还可以使用以下方法检查是否引发异常和警告:
方法 | 检查 | 新的 |
---|---|---|
assertRaises(exc,fun,* args,** kwds) | 有趣(* args,** kwds)引发了exc | |
assertRaisesRegexp(exc,r,fun,* args,** kwds) | fun(* args,** kwds)引发exc,并且消息匹配正则表达式r | 2.7 |
assertRaises(exception, callable, *args, **kwds)assertRaises(exception)
测试在调用callable
时使用传递给它的任何位置或关键字参数时会引发异常
assertRaises()
。如果发生异常
,则测试通过;如果发生另一个异常
,则为错误;如果未发生异常
,则发生错误。要捕获任何一组异常
,包含异常
类的元组可以作为例外
传递。
如果只给出异常
参数,则返回一个上下文管理器,以便测试下的代码可以内联写入,而不是作为函数写入:
with self.assertRaises(SomeException):
do_something()
上下文管理器将把捕获到的异常对象存储在它的exception
属性中。如果打算对引发的异常执行附加检查,这可能很有用:
with self.assertRaises(SomeException) as cm:
do_something()
the_exception = cm.exception
self.assertEqual(the_exception.error_code, 3)
在版本2.7中进行了更改:添加了assertRaises()
用作上下文管理器的功能。
assertRaisesRegexp(exception, regexp, callable, *args, **kwds)assertRaisesRegexp(exception, regexp)
像assertRaises()
但也测试正则表达式
在引发异常的字符串表示匹配。regexp
可能是一个正则表达式
对象或者是一个包含适合使用的正则表达式
的字符串re.search()
。例子:
self.assertRaisesRegexp(ValueError, "invalid literal for.*XYZ'$",
int, 'XYZ')
要么:
with self.assertRaisesRegexp(ValueError, 'literal'):
int('XYZ')
2.7版本的新功能。
还有其他方法用于执行更具体的检查,例如:
方法 | 检查 | 新的 |
---|---|---|
assertAlmostEqual(a,b) | round(ab,7)== 0 | |
assertNotAlmostEqual(a,b) | round(ab,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) | 不是r.search(s) | 2.7 |
assertItemsEqual(a,b) | 排序(a)==排序(b)并使用不可取的objs | 2.7 |
assertDictContainsSubset(a,b) | b中存在的所有键/值对 | 2.7 |
assertAlmostEqual(first, second, places=7, msg=None, delta=None)assertNotAlmostEqual(first, second, places=7, msg=None, delta=None)
测试第一
和第二
近似(或不近似)通过计算差,四舍五入到小数点的给定数目相等的地方
(默认7),并与零进行比较。请注意,这些方法将数值四舍五入到给定的小数位数
(即round()
函数)而不是有效数字
。
如果提供增量
而不是位置,
则第一个
和第二个
之间的差值必须小于或等于(或大于)delta
。
提供三角洲
和地方
提出了一个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)
根据方法名称测试第一个分别是>,> =,<或<= 第二个。如果不是,测试将失败:
>>> self.assertGreaterEqual(3, 4)
AssertionError: "3" unexpectedly not greater than or equal to "4"
2.7版本的新功能。
assertRegexpMatches(text, regexp, msg=None)
测试正则表达式
搜索与文本
匹配。如果失败,错误消息将包括模式和文本
(或模式和意外匹配的文本
部分)。regexp
可能是一个正则表达式
对象或者是一个包含适合使用的正则表达式
的字符串re.search()
。
2.7版本的新功能。
assertNotRegexpMatches(text, regexp, msg=None)
验证正则表达式
搜索与文本
不匹配。包含模式和匹配文本
部分的错误消息失败。regexp
可能是一个正则表达式
对象或者是一个包含适合使用的正则表达式
的字符串re.search()
。
2.7版本的新功能。
assertItemsEqual(actual, expected, msg=None)
测试期望
的序列包含与实际
相同的元素,而不管它们的顺序如何。如果没有,则会生成列出序列之间差异的错误消息。
比较实际值
和预期值
时,不会
忽略重复元素。它验证两个序列中每个元素是否具有相同的计数。它等同于它,但它也可以处理不可对象序列。assertEqual(sorted(expected), sorted(actual))
在Python 3中,这个方法被命名assertCountEqual
。
2.7版本的新功能。
assertDictContainsSubset(expected, actual, msg=None)
测试实际
字典中的键/值对是否是预期
字符集的超集。如果不是,则会生成列出缺失键和不匹配值的错误消息。
2.7版本的新功能。
自3.2版以来已弃用。
该assertEqual()
方法将相同类型的对象的相等性检查分派给不同类型特定的方法。这些方法已经用于大多数内置类型,但也可以使用addTypeEqualityFunc()
以下方法注册新方法:
addTypeEqualityFunc(typeobj, function)
注册一个名为by的类型特定方法assertEqual()
来检查两个完全相同的typeobj
(而不是子类)对象是否相等。函数
必须像两个位置参数一样,第三个msg = None关键字参数assertEqual()
。self.failureException(msg)
当检测到前两个参数之间的不平等时,它必须提高- 可能提供有用的信息并解释错误消息中的细节不等式。
2.7版本的新功能。
assertEqual()
下表中汇总了自动使用的特定于类型的方法列表。请注意,通常不需要直接调用这些方法。
方法 | 用于比较 | 新的 |
---|---|---|
assertMultiLineEqual(a,b) | 字符串 | 2.7 |
assertSequenceEqual(a,b) | 序列 | 2.7 |
assertListEqual(a,b) | 名单 | 2.7 |
assertTupleEqual(a,b) | 元组 | 2.7 |
assertSetEqual(a,b) | 设置或frozensets | 2.7 |
assertDictEqual(a,b) | http://stardict.sourceforge.net/Dictionaries.php下载 | 2.7 |
assertMultiLineEqual(first, second, msg=None)
测试了多串首先
是等于字符串第二
。如果不等于两个字符串的差异,则突出显示差异将包含在错误消息中。比较字符串时默认使用此方法assertEqual()
。
2.7版本的新功能。
assertSequenceEqual(seq1, seq2, msg=None, seq_type=None)
测试两个序列是否相等。如果提供了seq_type
,则seq1
和seq2
必须是seq_type的
实例,否则
将引发故障。如果序列不同,则会构造一个错误消息,显示两者之间的差异。
这个方法不是直接被调用assertEqual()
,而是用来实现assertListEqual()
和assertTupleEqual()
。
2.7版本的新功能。
assertListEqual(list1, list2, msg=None)assertTupleEqual(tuple1, tuple2, msg=None)
测试两个列表或元组是否相等。如果不是,则会构建一条仅显示两者之间差异的错误消息。如果两个参数中的任何一个参数都属于错误类型,也会引发错误。在比较列表或元组时,默认使用这些方法assertEqual()
。
2.7版本的新功能。
assertSetEqual(set1, set2, msg=None)
测试两组相等。如果不是,则会构造一个错误消息,列出各组之间的差异。比较设置或frozensets时默认使用此方法assertEqual()
。
如果set1
或set2
中没有一个set.difference()
方法,则失败。
2.7版本的新功能。
assertDictEqual(expected, actual, msg=None)
测试两个字典是否相同。如果不是,则会构造一个错误消息,显示字典中的差异。默认情况下会使用此方法比较调用中的字典assertEqual()
。
2.7版本的新功能。
最后TestCase
提供以下方法和属性:
fail(msg=None)
用msg
或None
错误信息无条件地表示测试失败。
failureException
这个类属性给出了测试方法引发的异常。如果一个测试框架需要使用一个专门的异常,可能需要携带更多的信息,那么它必须将这个异常小类化,以便与框架“公平”。这个属性的初始值是AssertionError
。
longMessage
如果设置为,True
那么传递给断言方法的任何显式失败消息都将追加到正常失败消息的末尾。正常消息包含有关所涉及对象的有用信息,例如来自assertEqual的消息显示了两个不等对象的repr。通过设置此属性,True
可以让您除了正常的错误信息之外还有自定义的错误信息。
此属性默认为False
,意味着传递给断言方法的自定义消息将会使常规消息无效。
通过在调用assert方法之前True
或False
之前分配实例属性,可以在单个测试中重写类设置。
2.7版本的新功能。
maxDiff
该属性通过assert方法控制差异输出的最大长度,该方法报告差异的差异。它默认为80 * 8个字符。受此属性影响的Assert方法assertSequenceEqual()
(包括委托给它的所有序列比较方法)assertDictEqual()
和assertMultiLineEqual()
。
设置maxDiff
为None
意味着没有最大长度的差异。
2.7版本的新功能。
测试框架可以使用以下方法收集测试信息:
countTestCases()
返回此测试对象表示的测试数量。对于TestCase
情况下,这将永远是1
。
defaultTestResult()
返回应该用于此测试用例类的测试结果类的实例(如果没有其他结果实例提供给该run()
方法)。
对于TestCase
情况下,这将永远是一个实例TestResult
; 子类TestCase
应该根据需要覆盖它。
id()
返回一个标识特定测试用例的字符串。这通常是测试方法的全名,包括模块和类名。
shortDescription()
返回测试的描述,或者None
没有提供描述。此方法的默认实现返回测试方法的文档字符串的第一行(如果可用)或None
。
addCleanup(function, *args, **kwargs)
添加一个函数来tearDown()
清理测试过程中使用的资源。函数将按照它们添加的顺序(LIFO)以相反的顺序调用。它们被调用时添加了任何参数和关键字参数addCleanup()
。
如果setUp()
失败,意味着tearDown()
没有被调用,那么添加的任何清理函数仍将被调用。
2.7版本的新功能。
doCleanups()
此方法在之后tearDown()
或之后被无条件地调用,setUp()
如果setUp()
引发异常。
它负责调用所添加的所有清理函数addCleanup()
。如果你需要清除函数被调用之前
到tearDown()
,那么你可以调用doCleanups()
。
doCleanups()
一次只能抛出一堆清理函数,因此可以随时调用。
2.7版本的新功能。
class unittest.FunctionTestCase(testFunc, setUp=None, tearDown=None, description=None)
该类实现了TestCase
允许测试运行器驱动测试的接口部分,但不提供测试代码可用于检查和报告错误的方法。这用于使用旧版测试代码创建测试用例,从而将其集成到unittest
基于测试框架的测试中。
7.1.1. 已弃用的别名
由于历史原因,其中一些TestCase
方法有一个或多个现在已被弃用的别名。下表列出了正确的名称及其弃用的别名:
方法名称 | 已弃用的别名(es) |
---|---|
assertEqual便() | failUnlessEqual,assertEquals |
assertNotEqual() | failIfEqual |
assertTrue() | failUnless,assert_ |
assertFalse() | failIf |
assertRaises() | failUnlessRaises |
assertAlmostEqual() | failUnlessAlmostEqual |
assertNotAlmostEqual() | failIfAlmostEqual |
自2.7版弃用:第二列中列出的别名
7.2. 分组测试
class unittest.TestSuite(tests=())
这个类代表了单个测试用例和测试套件的集合。该类提供了测试运行器所需的接口,以使其可以像其他任何测试用例一样运行。运行TestSuite
实例与遍历套件相同,单独运行每个测试。
如果给出了测试
,它必须是可用于最初构建套件的单个测试
用例或其他测试
套件的迭代。还提供了其他方法,以便稍后将测试
用例和套件添加到集合中。
TestSuite
对象的行为与TestCase
对象非常相似,只是它们并未实际执行测试。相反,它们用于将测试聚合到应该一起运行的测试组中。一些额外的方法可用于向TestSuite
实例添加测试:
addTest(test)
添加TestCase
或TestSuite
套件。
addTests(tests)
将迭代TestCase
和TestSuite
实例中的所有测试添加到此测试套件。
这相当于迭代测试
,调用addTest()
每个元素。
TestSuite
共享以下方法TestCase
:
run(result)
运行与此套件相关的测试,将结果
收集到作为结果
传递的测试结果
对象中。请注意,与之不同TestCase.run()
,TestSuite.run()
需要传入结果
对象。
debug()
运行与此套件相关的测试而不收集结果。这允许将测试引发的异常传播给调用者,并且可以用来支持在调试器下运行测试。
countTestCases()
返回此测试对象表示的测试数量,包括所有单个测试和子套件。
__iter__()
按a分组的测试TestSuite
总是通过迭代进行访问。子类可以懒惰地提供覆盖测试__iter__()
。请注意,此方法可能在单个套件上多次调用(例如,在计算测试或比较相等时),因此重复测试返回的测试必须相同。
在版本2.7中更改:在早期版本中,TestSuite
直接访问测试而不是迭代,所以覆盖__iter__()
不足以提供测试。
在TestSuite
对象的典型用法中,该run()
方法由一个TestRunner
而不是由最终用户测试工具调用。
7.3. 加载和运行测试
class unittest.TestLoader
所述TestLoader
类被用来创建从类和模块的测试套件。通常,不需要创建该类的实例; 该unittest
模块提供了一个可以共享的实例unittest.defaultTestLoader
。但是,使用子类或实例可以自定义一些可配置的属性。
TestLoader
对象有以下方法:
loadTestsFromTestCase(testCaseClass)
返回一个套件中包含的所有测试用例TestCase
派生testCaseClass
。
loadTestsFromModule(module)
返回给定模块
中包含的所有测试用例套件。此方法在模块
中搜索派生的类,TestCase
并为为该类定义的每个测试方法创建类的实例。
注意
虽然使用TestCase
衍生类的层次结构可以方便地共享fixtures和helper函数,但是在基类上定义测试方法并不打算直接实例化,但这种方法并不能很好地发挥作用。但是,如果灯具不同并在子类中定义,则这样做会很有用。
如果一个模块提供了一个load_tests
函数,它将被调用来加载测试。这允许模块自定义测试加载。这是load_tests
协议。
在版本2.7中更改:支持load_tests
添加。
loadTestsFromName(name, module=None)
返回给定字符串说明符的所有测试用例。
指定器名称
是“带点名称
”,其可以解决要么模块,测试用例类,测试用例类内的测试法,TestSuite
实例或它返回一个可调用对象TestCase
或TestSuite
实例。这些检查按照此处列出的顺序应用; 也就是说,可能的测试用例类中的方法将被选为“测试用例类中的测试方法”,而不是“可调用对象”。
例如,如果您的模块SampleTests
包含带有三种测试方法(,和)的TestCase
派生类,则说明符会导致此方法返回一个将运行所有三种测试方法的套件。使用说明符会导致它返回一个只运行测试方法的测试套件。说明符可以引用尚未导入的模块和包; 他们将作为副作用进口。SampleTestCasetest_one()test_two()test_three()'SampleTests.SampleTestCase''SampleTests.SampleTestCase.test_two'test_two()
该方法可以选择性地解析相对于给定模块的名称
。
loadTestsFromNames(names, module=None)
类似于loadTestsFromName()
,但是采用一系列名称而不是单一名称。返回值是一个测试套件,它支持为每个名称定义的所有测试。
getTestCaseNames(testCaseClass)
返回在testCaseClass中
找到的方法名称的排序顺序; 这应该是一个子类TestCase
。
discover(start_dir, pattern='test*.py', top_level_dir=None)
通过从指定的开始目录递归到子目录中查找所有测试模块,并返回包含它们的TestSuite对象。只有与模式
匹配的测试文件才会被加载。(使用shell风格模式
匹配。)只有可导入的模块名称(即有效的Python标识符)才会被加载。
所有测试模块必须可以从项目的顶层导入。如果起始目录不是顶层目录,则顶层目录必须单独指定。
如果导入模块失败,例如由于语法错误,那么这将被记录为单个错误,并且发现将继续。
如果测试
包名称(带有的目录__init__.py
)与该模式
匹配,则会检查该包是否有load_tests
函数。如果存在,那么它将被加载器
,测试
,模式
调用。
如果load_tests
存在,那么发现并没有
递归放入包中,load_tests
负责加载所有测试包。
该模式故意不作为加载程序属性存储,以便程序包可以继续自行发现。存储top_level_dir
,因此load_tests
不需要将此参数传入loader.discover()
。
start_dir
可以是虚线模块名称以及目录。
2.7版本的新功能。
TestLoader
的以下属性可以通过子类或实例上的赋值来配置:
testMethodPrefix
提供方法名称前缀的字符串,将被解释为测试方法。默认值是'test'
。
这影响getTestCaseNames()
和所有的loadTestsFrom*()
方法。
sortTestMethodsUsing
函数用于在对它们进行排序时比较方法名称getTestCaseNames()
以及所有loadTestsFrom*()
方法。默认值是内置cmp()
函数; 该属性也可以设置None
为禁用排序。
suiteClass
从测试列表构造测试套件的可调用对象。在结果对象上不需要任何方法。默认值是TestSuite
类。
这影响了所有的loadTestsFrom*()
方法。
class unittest.TestResult
该类用于编译有关哪些测试已成功并失败的信息。
一个TestResult
对象存储一组测试的结果。在TestCase
和TestSuite
班保证结果正确记录; 测试作者不需要担心记录测试的结果。
构建在最上面的测试框架unittest
可能需要访问TestResult
为报告目的运行一组测试所生成的对象; 为此目的TestResult
,TestRunner.run()
方法返回一个实例。
TestResult
实例具有以下在检查运行一组测试的结果时将会感兴趣的属性:
errors
包含TestCase
实例和字符串的2元组的列表,其中包含格式化的回溯。每个元组代表一个引发意外异常的测试。
在版本2.2中进行了更改:包含格式化的追溯而不是sys.exc_info()
结果。
failures
包含TestCase
实例和字符串的2元组的列表,其中包含格式化的回溯。每个元组代表一个测试,其中使用这些TestCase.assert*()
方法显式地发送了失败信号。
在版本2.2中进行了更改:包含格式化的追溯而不是sys.exc_info()
结果。
skipped
包含TestCase
实例和字符串的2元组的列表,其中包含跳过测试的原因。
2.7版本的新功能。
expectedFailures
包含TestCase
实例和字符串的2元组的列表,其中包含格式化的回溯。每个元组代表测试用例的预期失败。
unexpectedSuccesses
包含TestCase
标记为预期失败但成功的实例的列表。
shouldStop
设置为True
执行测试时应该停止stop()
。
testsRun
迄今为止运行的测试总数。
buffer
如果设置为true,sys.stdout
并且sys.stderr
将在之间进行缓冲startTest()
和stopTest()
被调用。收集到的输出只会回显到真实状态sys.stdout
,sys.stderr
如果测试失败或错误。任何输出也附加到失败/错误消息。
2.7版本的新功能。
failfast
如果设置为true,stop()
则会在第一次失败或错误时调用,从而停止测试运行。
2.7版本的新功能。
wasSuccessful()
返回True
如果所有测试跑这么远都过去了,否则返回False
。
stop()
可以调用此方法来指示正在运行的测试集应通过设置shouldStop
属性来中止True
。TestRunner
对象应该尊重这个标志并返回而不需要运行任何附加测试。
例如,TextTestRunner
当用户通过键盘发出中断时,该类将使用此功能来停止测试框架。提供TestRunner
实现的交互式工具可以以类似的方式使用它。
TestResult
该类的以下方法用于维护内部数据结构,并可以在子类中进行扩展以支持其他报告要求。这在构建支持交互式报告而运行测试的工具时特别有用。
startTest(test)
当测试
用例测试
即将运行时调用。
stopTest(test)
无论结果如何,在测试用例测试
执行后调用。
startTestRun()
在执行任何测试之前调用一次。
2.7版本的新功能。
stopTestRun()
所有测试执行完毕后调用一次。
2.7版本的新功能。
addError(test, err)
当测试
用例测试
引发意外的异常时调用。err
是由以下形式返回的形式的元组sys.exc_info()
:(type, value, traceback)
。
默认实现将元组附加(test, formatted_err)
到实例的errors
属性,其中formatted_err
是从err
派生的格式化回溯。
addFailure(test, err)
当测试
用例测试
指示失败时调用。err
是由以下形式返回的形式的元组sys.exc_info()
:(type, value, traceback)
。
默认实现将元组附加(test, formatted_err)
到实例的failures
属性,其中formatted_err
是从err
派生的格式化回溯。
addSuccess(test)
当测试
用例测试
成功时调用。
默认实现什么都不做。
addSkip(test, reason)
当测试
用例测试
被跳过时调用。原因
是测试
给跳过的原因
。
默认实现将元组附加(test, reason)
到实例的skipped
属性。
addExpectedFailure(test, err)
当测试
用例测试
失败时调用,但用expectedFailure()
装饰器标记。
默认实现将元组附加(test, formatted_err)
到实例的expectedFailures
属性,其中formatted_err
是从err
派生的格式化回溯。
addUnexpectedSuccess(test)
当测试
用例测试
用expectedFailure()
装饰器标记但成功时调用。
默认实现将测试附加到实例的unexpectedSuccesses
属性。
class unittest.TextTestResult(stream, descriptions, verbosity)
一个具体的实现TestResult
使用的TextTestRunner
。
2.7版本中的新功能:此类是以前命名的_TextTestResult
。旧名称仍作为别名存在,但不推荐使用。
unittest.defaultTestLoader
TestLoader
该类的实例打算共享。如果不需要自定义,TestLoader
则可以使用此实例,而不是重复创建新实例。
class unittest.TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=1, failfast=False, buffer=False, resultclass=None)
一个基本的测试运行器实现,打印标准错误的结果。它有几个可配置的参数,但实质上非常简单。运行测试套件的图形应用程序应提供替代实现。
_makeResult()
此方法返回的实例TestResult
所使用run()
。它不打算直接调用,但可以在子类中重写以提供自定义TestResult
。
_makeResult()
将TextTestRunner
构造函数中传递的类或可调用实例化为resultclass
参数。TextTestResult
如果没有resultclass
提供,它默认为。结果类用以下参数实例化:
stream, descriptions, verbosity
unittest.main([module[, defaultTest[, argv[, testRunner[, testLoader[, exit[, verbosity[, failfast[, catchbreak[, buffer]]]]]]]]]])
一个命令行程序,从模块
中加载一组测试并运行它们; 这主要是为了使测试模块
方便地执行。此函数最简单的用法是在测试脚本的末尾包含以下行:
if __name__ == '__main__':
unittest.main()
您可以通过传递详细信息参数来运行更详细的信息测试:
if __name__ == '__main__':
unittest.main(verbosity=2)
defaultTest
参数是测试如果通过指定没有测试名运行名argv的
。如果未指定或None
没有通过argv
提供测试名称,则会运行模块
中找到的所有测试。
argv的
参数可以是传递给程序的选项列表,第一个元素是程序名称。如果未指定或使用None
的值sys.argv
。
所述的TestRunner
参数可以是一个测试运行类或它的一个已创建的实例。默认情况下,带有退出代码的main
调用sys.exit()
指示测试成功或失败。
testLoader
参数必须是一个TestLoader
实例,并默认为defaultTestLoader
。
main
通过传递参数支持交互式解释器的使用exit=False
。这会在标准输出中显示结果而不调用sys.exit()
:
>>> from unittest import main
>>> main(module='test_module', exit=False)
故障快速转移
,catchbreak
和缓冲
参数具有与相同名称的命令行选项的相同的效果。
调用main
实际上会返回TestProgram
该类的一个实例。这将测试结果存储为result
属性。
在2.7版更改:将退出
,冗长
,故障快速转移
,catchbreak
和缓冲区
参数中添加。
7.3.1. load_tests协议
2.7版本的新功能。
模块或包可以定制在正常测试运行期间如何从它们加载测试,或者通过实现一个名为的函数来测试发现load_tests
。
如果一个测试模块定义了load_tests
,它将被TestLoader.loadTestsFromModule()
以下参数调用:
load_tests(loader, standard_tests, None)
它应该返回一个TestSuite
。
loader
是加载
的实例TestLoader
。standard_tests
是默认从模块加载
的测试。测试模块通常只想添加或移除标准测试集中的测试。加载
包作为测试发现的一部分时使用第三个参数。
load_tests
从特定的一组TestCase
类中加载测试的典型函数可能如下所示:
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
。
注意
默认模式是'test*.py'
。它匹配所有以任何测试目录开头'test'
但不
匹配任何测试目录的Python文件。
类似的模式'test*'
将匹配测试包和模块。
如果包__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
8.类别和模块夹具
类和模块级别的固定装置在中实现TestSuite
。当测试套件遇到来自新类的测试时,则tearDownClass()
从前一个类(如果有的话)被调用,然后setUpClass()
从新类中调用。
类似地,如果测试来自与先前测试不同的模块,tearDownModule
则从之前的模块开始运行,然后setUpModule
从新模块运行。
在所有测试运行最后tearDownClass
并且tearDownModule
运行之后。
请注意,共享装置在测试并行化等潜在功能方面表现不佳,并且会破坏测试隔离。他们应该小心使用。
由unittest测试加载器创建的测试的默认排序是将来自相同模块和类的所有测试分组在一起。这将导致setUpClass
/ setUpModule
(等)每个类和模块只被调用一次。如果随机化订单,以便来自不同模块和类的测试彼此相邻,则可以在单次测试中多次调用这些共享夹具功能。
共享灯具不适用于具有非标准订购的套件。一个BaseTestSuite
仍然存在不希望支持共享夹具框架。
如果在共享夹具功能之一中发生任何异常,则测试报告为错误。因为没有相应的测试实例,所以创建一个_ErrorHolder
对象(与a具有相同的接口TestCase
)来表示错误。如果你只是使用标准的unittest测试运行器,那么这个细节并不重要,但如果你是一个框架作者,它可能是相关的。
8.1. 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
异常,那么该类将被报告为被跳过而不是作为错误。
8.2。setUpModule和tearDownModule
这些应该作为函数来实现:
def setUpModule():
createConnection()
def tearDownModule():
closeConnection()
如果在某个时候发生异常setUpModule
,则模块中的所有测试都不会运行,并且tearDownModule
不会运行。如果异常是一个SkipTest
异常,那么该模块将被报告为被跳过而不是错误。
9.信号处理
单元测试的-c/--catch
命令行选项以及catchbreak
参数可以unittest.main()
在测试运行期间提供更友好的control-C处理。在启用catch break行为的情况下,control-C将允许当前正在运行的测试完成,然后测试运行将结束并报告迄今为止的所有结果。第二个控件c会KeyboardInterrupt
以通常的方式提出。
control-c处理信号处理程序试图保持与安装自己的signal.SIGINT
处理程序的代码或测试的兼容性。如果unittest
处理程序被调用但不是
已安装的signal.SIGINT
处理程序,即它已被替换为被测系统并委托给它,则它会调用默认处理程序。这通常是代码的预期行为,该代码取代已安装的处理程序并委托给它。对于需要unittest
control-c处理禁用的单个测试,removeHandler()
可以使用装饰器。
为了在测试框架中启用control-c处理功能,框架作者有几个实用功能。
unittest.installHandler()
安装control-c处理程序。当signal.SIGINT
收到a时(通常是响应用户按下control-c)所有已注册的结果已stop()
被调用。
2.7版本的新功能。
unittest.registerResult(result)
TestResult
为control-c处理注册一个对象。注册结果会存储对它的弱引用,所以它不会阻止垃圾收集结果。
TestResult
如果未启用control-c处理,则注册对象没有副作用,因此测试框架可以无条件地注册它们创建的所有结果,而不管是否启用处理。
2.7版本的新功能。
unittest.removeResult(result)
删除注册结果。一旦结果被删除,那么stop()
将不再调用该结果对象来响应control-c。
2.7版本的新功能。
unittest.removeHandler(function=None)
当没有参数的情况下调用这个函数会删除control-c处理程序,如果它已经安装。该函数也可以用作测试装饰器,在测试执行时临时移除该处理器:
@unittest.removeHandler
def test_signal_handling(self):
...
2.7版本的新功能。