版本支持:
Python version 2.7.14
unittest version 2.1
1.定义
Python 单元测试框架unittest,有时被称为PyUnit,是Python版本的JUnit
unittest支持自动化测试,组成结构:
test fixture(测试装置):执行测试所需的准备工作,以及任何关联清理操作。
test case(测试用例):是单元测试的最小单位。 提供了一个基类, 可用于创建新的测试用例。
test suit(测试集):它用于聚合应该一起执行的test case。
test runner(测试执行):是一个协调测试执行并向用户提供结果的组件。
1.类TestCase/FuncitonTestCase:提供test case和test fixture,test fixture包括setUp(),tearDown(),这两个方法可以被重写,setUp()提供初始化操作,tearDown()提供清理操作。
2.类TestSuite:提供test suit
3.类TextTestRunner:作为一个test runner的例子且报告测试结果在默认的错误流上
4.类TestResult:提供结果对象
5.一个单独方法的对象run():它接受TestCase或TestSuite对象作为参数,并且返回结果对象
2.基本示例
模块提供了一组丰富的工具,用于构建和运行测试。这部分示范了很小的一部分工具,但是却能满足绝大部分用户的需求。
这边有一段小代码用于测试 模块的三个方法:
import unittestclass 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()
测试用例通过 的子类创建。在测试用例中,这三个独立的测试方法的方法名称都以 test打头。该命名规范用于告诉测试者哪些方法用于测试。
每一个测试的核心是通过调用)方法去检查结果是否和期望的结果相同。方法用于核实最终状态;或者调用方法去检查是否抛出期望的异常。通过使用这些方法来代替断言方法。所以,测试者可以积累所有的测试结果并产生一个报告。
如果定义了方法,测试者在每次测试之前都会运行该方法。同样的,如果定义了 方法,测试者在每次测试后都会调用该方法。
最后两句代码展示了一个简单的运行测试的方法。 提供命令行接口的测试脚本。当从命令行中运行时,上面的脚本将产生一个看起来像这样的输出:
...----------------------------------------------------------------------Ran 3 tests in 0.000sOK
除了 方法, 还有其他的方法来运行一个更精细的控制测试、更简洁的输出,并没有规定必须从命令行运行。例如,最后两行可能被替换:
suite = unittest.TestLoader().loadTestsFromTestCase(TestStringMethods)unittest.TextTestRunner(verbosity=2).run(suite)
从解释器或另一个脚本运行修改后的脚本产生如下输出:
test_isupper (__main__.TestStringMethods) ... oktest_split (__main__.TestStringMethods) ... oktest_upper (__main__.TestStringMethods) ... ok----------------------------------------------------------------------Ran 3 tests in 0.001sOK
上面的示例展示了最常用的测试功能,足以满足许多日常的测试需求 。文档的其余部分将从基本原理中探索完整的特性集。
3.命令行接口
unittest模块可以从命令行对于模块,类甚至单独的测试方法进行测试。
python -m unittest test_module1 test_module2python -m unittest test_module.TestClasspython -m unittest test_module.TestClass.test_method
您可以通过任何模块名称的组合,以及完全限定的类或方法名来传入列表。
通过传入-v标志,您可以更详细地运行测试(更高的冗长)
python -m unittest -v test_module
对于所有命令行选项的列表:
python -m unittest -h
在版本2.7中更改:在早期版本中,只可能运行单独的测试方法而不是模块或类。
3.1命令行选项
unittest 支持这些命令行选项:
- -b, --buffer
-
在测试运行期间,标准输出和标准错误流被缓冲。在通过测试期间的输出被丢弃。输出在测试失败或错误中得到了正常的响应,并添加到故障消息中。
- -c, --catch
-
在测试运行期间,Control-C等待当前测试结束,然后报告所有结果。第二个control-C增加了正常的keyboard中断异常。
请参阅提供此功能的函数的信号处理。
- -f, --failfast
-
在第一个错误或失败时停止测试。
新版本2.7命令行选项-b,-c 和 -f 被添加。
命令行还可以用于测试发现,用于在一个项目中运行所有的测试,或者仅仅是一个子集。
4.测试发现
Unittest支持简单的测试发现。为了与测试发现兼容,所有的测试文件都必须是从项目的顶级目录中导入的模块或包(这意味着它们的文件名必须是有效的标识符)。
测试发现是在testloader.discover() 中实现的,但是也可以从命令行中使用。基本的命令行用法是:
cd project_directorypython -m unittest discover
discover命令有如下参数:
-
详细输出
-v
,
--verbose
-
开始发现的目录(默认)
-s
,
--start-directory
directory
-
匹配测试文件的模式(默认
test*.py
)
-p
,
--pattern
pattern
-
顶级的项目目录(默认启动目录
-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。测试,作为开始目录。然后,您提供的软件包名称将被导入,并且它在文件系统上的位置将用作开始目录。
注意:测试发现通过导入测试来加载测试。一旦测试发现从您指定的开始目录中找到所有的测试文件,它就会将路径转换为导入的包名。例如foo / bar /baz.py将被导入为foo。bar。baz。
如果您在全球安装了一个软件包,并尝试在不同的软件包副本上测试发现,那么导入可能会发生在错误的地方。如果发生这种情况,测试发现将警告您并退出。
如果您将开始目录作为包名而不是路径到目录,那么您会发现它从您想要的位置的任何一个位置都是您想要的位置,所以您将不会得到警告。
测试模块和包可以通过loadtest协议定制测试加载和发现。
5.组织测试代码
单元测试的基本构建块是测试用例——必须设置并检查正确性的单个场景。在unittest中,测试用例由unittest的TestCase类的实例来表示。要制作您自己的测试用例,您必须编写TestCase的子类,或者使用FunctionTestCase。
testcase派生类的一个实例是一个可以完全运行单个测试方法的对象,以及可选的设置和收集的代码。
TestCase实例的测试代码应该完全是自包含的,这样它就可以在孤立的状态下运行,也可以在任意数量的其他测试用例中运行。
最简单的TestCase子类将简单地覆盖runTest()方法,以执行特定的测试代码:
import unittestclass DefaultWidgetSizeTestCase(unittest.TestCase): def runTest(self): widget = Widget('The widget') self.assertEqual(widget.size(), (50, 50), 'incorrect default size')
注意,为了测试某些东西,我们使用TestCase基类提供的assert()方法之一。如果测试失败,将会出现一个异常,unittest会将测试用例识别为失败。任何其他异常都将被视为错误。这可以帮助你确定问题所在:失败是由不正确的结果引起的——在你预期的情况下。错误是由不正确的代码造成的——例如,错误的函数调用导致的类型错误。
运行测试用例的方法将在后面描述。现在,请注意,要构造这样一个测试用例的实例,我们调用它的构造函数而不带参数:
testCase = DefaultWidgetSizeTestCase()
现在,这样的测试用例可能很多,而且它们的设置可以是重复的。在上面的例子中,在每个百件小部件测试用例的子类中构造一个小部件将意味着不雅观的重复。
幸运的是,我们可以通过实现一个叫做setUp()的方法来排除这种设置代码,测试框架会在运行测试时自动调用我们:
import unittestclass 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 unittestclass SimpleWidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget('The widget') def tearDown(self): self.widget.dispose() self.widget = None
如果setUp()成功了,那么tearDown()方法将运行runTest()是否成功。
这种测试代码的工作环境称为fixture。
通常,许多小的测试用例将使用相同的fixture。
在这种情况下,我们最终将子类化SimpleWidgetTestCase DefaultWidgetSizeTestCase等成许多小类的一种方法。这是一项耗时又令人沮丧的工作,因此与JUnit一样,unittest提供了一种更简单的机制:import unittestclass 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()方法中的一个。为每个实例分别创建和销毁小部件。在创建实例时,我们必须指定要运行的测试方法。我们通过在构造函数中传递方法名来做到这一点:
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 defaultsize()和widgettestcase.test size。
TestLoader会使用“test”方法名前缀来自动识别测试方法。注意,将运行各种测试用例的顺序是通过对字符串的内置顺序排序的测试函数名来确定的。
通常情况下,将测试用例组合在一起是可取的,这样就可以同时运行整个系统的测试。
这很容易,因为TestSuite实例可以被添加到TestSuite中,就像TestCase实例可以被添加到TestSuite一样:suite1 = module1.TheTestSuite()suite2 = module2.TheTestSuite()alltests = unittest.TestSuite([suite1, suite2])
您可以将测试用例和测试套件的定义放在与测试代码相同的模块中(比如widget.py),但是将测试代码放在单独的模块中有几个好处,比如testwidget.py:
- 测试模块可以独立于命令行运行。
- 测试代码可以更容易地与已发布的代码分开。
- 如果没有充分的理由,改变测试代码来适应它所测试的代码的诱惑就会减少。
- 测试代码的修改要比它测试的代码要少得多。
- 测试代码可以更容易地重构。
- 用C编写的模块的测试必须在单独的模块中,那么为什么不一致呢?
- 如果测试策略改变了,就不需要更改源代码了。
6.重用旧的测试代码
有些用户会发现他们有他们想要从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支持测试提高断言错误以指示测试失败。
但是,建议您使用显式testcase.fail()和testcase.assert()方法,因为unittest的未来版本可能会以不同的方式对待断言错误。备注:
尽管FunctionTestCase可以用来快速地将现有的测试基础转换为基于unittest的系统,但不推荐这种方法。
花点时间来设置适当的TestCase子类将使未来的测试重构变得更加容易。在某些情况下,现有的测试可能是使用doctest模块编写的。
如果是这样,doctest提供了一个DocTestSuite类,可以自动构建unittest。来自现有基于doctest的测试的TestSuite实例。7.跳过测试和预期的失败
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.005sOK (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")
在测试中,当需要跳过时,让decorator调用skip(),从而轻松地滚动自己的跳过装饰器。
这个修饰器跳过了测试,除非传递的对象有一个特定的属性:def skipUnlessHasattr(obj, attr): if hasattr(obj, attr): return lambda func: func return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))
下面的decorator实现了测试跳跃和预期的失败:
-
无条件地跳过装饰测试。
理性应该描述为什么要跳过这个测试。
unittest.
skip
(reason) -
如果condition条件为真,就跳过装饰测试
unittest.
skipIf
(condition, reason) -
除非condition条件为真,才跳过这个装饰测试
unittest.
skipUnless
(condition, reason) -
将测试标记为预期的失败。如果测试在运行时失败,那么测试就不会被算为失败。
unittest.
expectedFailure
() - exception
-
这个异常被提出跳过一个测试。
通常,您可以使用testcase.skiptest()或一个跳过的decorator,而不是直接提高它。
unittest.
SkipTest
(reason) 跳过的测试将不会有setUp()或tearDown()在它们周围运行。
跳过的类不会有setUpClass()或tearDownClass()运行。8.测试用例Test cases
class unittest.
TestCase
(methodName='runTest')
TestCase类的实例代表了unittest宇宙中最小的可测试单元。该类旨在作为基类使用,具体的测试由具体的子类实现。该类实现了测试运行器所需要的接口,允许它驱动测试,测试代码可以使用这些方法检查和报告各种故障。
TestCase的每个实例都会运行一个单独的测试方法:方法名方法名。
如果你们还记得,我们之前有一个例子是这样的:def suite(): suite = unittest.TestSuite() suite.addTest(WidgetTestCase('test_default_size')) suite.addTest(WidgetTestCase('test_resize')) return suite
在这里,我们创建了WidgetTestCase的两个实例,每个实例都运行一个测试。
方法名字默认为runTest()
TestCase实例提供了三组方法:一组用来运行测试,另一组用于测试实现来检查条件和报告失败,以及一些查询方法,允许收集关于测试本身的信息。
第一个组中的方法(运行测试)是:
setUp()
方法称为准备测试夹具。
这叫做之前立即调用测试方法;AssertionError或SkipTest以外,任何异常提出这个方法将被认为是一个错误,而不是一个测试失败。没有默认的实现。tearDown()
在测试方法被调用后立即调用方法,并记录结果。即使测试方法引发了异常,也会调用这种方法,因此子类中的实现可能需要特别注意检查内部状态。除了断言错误或SkipTest之外,任何异常都将被认为是额外的错误,而不是测试失败(因此增加了报告错误的总数)。如果setUp()成功了,不管测试方法的结果如何,这个方法都将被调用。默认的实现什么都不做。
setUpClass()
一个类方法,在一个单独的类运行之前调用。
setUpClass作为唯一的参数被调用,并且必须作为classmethod()来修饰:@classmethoddef setUpClass(cls): ...
tearDownClass()
一个类方法在一个单独的类中被调用,然后运行。tearDownClass作为唯一的参数被调用,并且必须作为classmethod()来装饰:
@classmethoddef tearDownClass(cls): ...
run(result=None)
运行测试,将结果收集到作为结果传递的测试结果对象中。如果结果被省略或者没有,则创建一个临时性的结果对象(通过调用defaultTestResult()方法)并使用它。result对象不会返回run()的调用者。
通过简单地调用TestCase实例也可以得到相同的效果。
skipTest(reason)
在测试方法或设置()中调用这个方法跳过了当前的测试。更多信息,请参阅跳过测试和预期失败。
debug()
在不收集结果的情况下运行测试。这允许将测试提高的异常传播给调用者,并且可以用于支持调试器下的运行测试。
TestCase类提供几种assert方法来检查和报告故障。下表列出了最常用的方法(请参阅下面的表以获取更多assert方法):
Method | Checks that | New in |
---|---|---|
a == b | ||
a != b | ||
bool(x) is True | ||
bool(x) is False | ||
a is b | 2.7 | |
a is not b | 2.7 | |
x is None | 2.7 | |
x is not None | 2.7 | |
a in b | 2.7 | |
a not in b | 2.7 | |
isinstance(a, b) | 2.7 | |
not isinstance(a, b) | 2.7 |
所有的断言方法(除了assertRaises(),assertRaisesRegexp()) 接受一条消息参数,如果指定了,则用作失败的错误消息(请参阅longMessage)。
-
测试第一个参数和第二个参数是相等的. 如果值不相等,则测试失败
另外, 如果第一个和第二个是相同的类型和一个列表,元祖,字典,集,frozenset或者 unicode或任何类型的子类与addTypeEqualityFunc()函数将调用特定类型平等以生成一个更有用的默认错误消息(参见特定类型的列表方法).
assertEqual
(first, second, msg=None) -
测试第一个参数和第二个参数是不相等的. 如果值相等,则测试失败
assertNotEqual
(first, second, msg=None) -
测试expr是真值 (或假值).等同于判断expr是true或false
expr是真
(assertIs(expr, True)
). (assertEqual(a, b)
代替assertTrue(a == b)
), 因为他们在错误机制中能提供一个更好的错误消息
assertTrue
(expr, msg=None) assertFalse
(expr, msg=None) -
测试first和second是不是同一个对象.
assertIs
(first, second, msg=None) assertIsNot
(first, second, msg=None) -
测试expr是不是
None
.
assertIsNone
(expr, msg=None) assertIsNotNone
(expr, msg=None) -
测试first在或不在集合second.中
assertIn
(first, second, msg=None) assertNotIn
(first, second, msg=None) -
测试obj是或不是c/s的实例 (一个类或者一组类,可以用
方法
). T检查正确的类型用 .
assertIsInstance
(obj, cls, msg=None) assertNotIsInstance
(obj, cls, msg=None) 也可以使用以下方法检查异常和警告:
Method | Checks that | New in |
---|---|---|
fun(*args, **kwds) raises exc | ||
fun(*args, **kwds) raises exc and the message matches regex r | 2.7 |
assertRaises
(exception, callable, *args, **kwds)
assertRaises
(exception)
当调用callable时,可以通过任何位置或关键字参数调用callable()来测试异常。如果抛出异常,则测试通过,如果出现异常,则会出现错误,如果不抛出异常,则会失败。为了捕获任何一组异常,一个包含异常类的元组可以作为异常传递。
如果只给出异常参数,则返回一个上下文管理器,以便测试下的代码可以内联而不是作为一个函数来编写:
with self.assertRaises(SomeException): do_something()
上下文管理器会将捕获的异常对象储存在异常属性中。如果意图是对所提出的异常进行额外的检查,那么这将非常有用:
with self.assertRaises(SomeException) as cm: do_something()the_exception = cm.exceptionself.assertEqual(the_exception.error_code, 3)
assertRaisesRegexp
(exception, regexp, callable, *args, **kwds)
assertRaisesRegexp
(exception, regexp)
与断言()相似,但也测试regexp匹配凸起异常的字符串表示。regexp可以是一个正则表达式对象,也可以是包含正则表达式的字符串,该表达式适用于re.search()。例子:
self.assertRaisesRegexp(ValueError, "invalid literal for.*XYZ'$", int, 'XYZ')
with self.assertRaisesRegexp(ValueError, 'literal'): int('XYZ')
还有其他一些方法用于执行更具体的检查,例如:
Method | Checks that | New in |
---|---|---|
round(a-b, 7) == 0 | ||
round(a-b, 7) != 0 | ||
a > b | 2.7 | |
a >= b | 2.7 | |
a < b | 2.7 | |
a <= b | 2.7 | |
r.search(s) | 2.7 | |
not r.search(s) | 2.7 | |
sorted(a) == sorted(b) and works with unhashable objs | 2.7 | |
all the key/value pairs in a exist in b | 2.7 |
-
测试第一和第二是近似(或不近似)相等的,计算差值,四舍五入到给定的小数位数(默认7),并将其与零进行比较。注意,这些方法将值四舍五入到小数点后的位数(如圆()函数),而不是有效的数字。
如果delta是提供的而不是位置,那么第一和第二之间的差别必须小于或等于(或大于)增量。
同时提供delta和位置也会产生一个类型错误。
assertAlmostEqual
(first, second, places=7, msg=None, delta=None) assertNotAlmostEqual
(first, second, places=7, msg=None, delta=None) 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"
-
测试regexp搜索匹配文本。如果发生故障,错误消息将包括模式和文本(或模式和意外匹配的文本部分)。regexp可以是一个正则表达式对象,也可以是包含正则表达式的字符串,该表达式适用于re.search()。
assertRegexpMatches
(text, regexp, msg=None) assertNotRegexpMatches
(text, regexp, msg=None) 验证regexp search不匹配文本。错误消息包括模式和匹配的文本部分失败。regexp可以是一个正则表达式对象,也可以是包含正则表达式的字符串,该表达式适用于re.search()。 assertItemsEqual
(actual, expected, msg=None) 无论顺序如何,测试序列预期包含的元素与实际的元素相同。当它们不这样做时,会生成一个错误消息,列出序列之间的差异。
在比较实际和预期时,重复的元素不会被忽略。它将验证每个元素在两个序列中是否具有相同的计数。它相当于断言(已排序的(预期的),排序的(实际的)),但是它也适用于不可行的对象序列。
在python3中,这个方法被命名为“断言”。
assertDictContainsSubset
(expected, actual, msg=None)
测试字典中的键/值对是否是预期的超集。如果没有,则会生成一个错误消息,其中列出了丢失的钥匙和不匹配的值。
assertEqual()方法将同一类型的对象的平等检查分派给不同类型的方法。这些方法已经实现了大多数内置类型,但也可以使用addTypeEqualityFunc()来注册新方法:
-
登记一个特定于特定类型的方法,由断言()来检查两个对象是否是相同类型obj(而不是子类)比较相等。函数必须接受两个位置参数,第三个msg=None关键字参数,就像断言()一样。当检测到前两个参数之间的不平等时,它必须提高self。failureexception(msg)——可能提供有用的信息,并解释错误消息中细节的不平等。
addTypeEqualityFunc
(typeobj, function) 下面的表总结了由断言()自动使用的特定于类型的方法的列表。请注意,通常不需要直接调用这些方法。
Method | Used to compare | New in |
---|---|---|
strings | 2.7 | |
sequences | 2.7 | |
lists | 2.7 | |
tuples | 2.7 | |
sets or frozensets | 2.7 | |
dicts | 2.7 |
-
-
测试多行字符串首先等于字符串秒。当不等于两根突出差异的字符串的差异时,将会包含在错误消息中。默认情况下,当比较Unicode字符串时,该方法会被默认使用。
assertMultiLineEqual
(first, second, msg=None)-
测试这两个序列是相等的。如果提供seqtype,那么seq1和seq2都必须是seqtype的实例,否则将会出现故障。如果序列是不同的,则会构造一个显示两者之间差异的错误消息。
这种方法不是由断言()直接调用的,但是它用于实现果断的()和断言()
assertSequenceEqual
(seq1, seq2, msg=None, seq_type=None)-
测试两个列表或元组是相等的。如果没有,则构造一个只显示两者之间差异的错误消息。如果参数的类型都是错误的,则会出现错误。当比较列表或元组与断言()时,这些方法是默认使用的。
assertListEqual
(list1, list2, msg=None)assertTupleEqual
(tuple1, tuple2, msg=None)-
两个集合相等的测试。如果没有,则会构造一个错误消息,列出集合之间的差异。当比较set或frozenset()时,默认使用此方法。
如果set1或set2中的任一种都没有set.差分()方法,则失败。
assertSetEqual
(set1, set2, msg=None)-
测试两个字典是相等的。如果没有,则会构造一个显示字典中不同之处的错误消息。默认情况下,这个方法将用于比较字典中的字典和断言()。
assertDictEqual
(expected, actual, msg=None)Finally the provides the following methods and attributes:
-
无条件地发出测试失败的信号,使用msg或没有错误消息。
fail
(msg=None)-
该类属性提供了由测试方法引发的异常。如果一个测试框架需要使用专门的异常,可能是为了传递额外的信息,那么它必须继承这个异常,以便“公平地”使用框架。这个属性的初始值是断言错误
failureException
-
如果将其设置为True,那么您传递给assert方法的任何显式失败消息都将追加到正常故障消息的末尾。正常的消息包含关于所涉及对象的有用信息,例如来自断言的消息向您显示了两个不相等对象的repr。将这个属性设置为True可以让您除了普通的错误消息之外还有一个自定义的错误消息。
这个属性默认为False,这意味着传递给assert方法的定制消息将使正常消息保持静默。
在调用assert方法之前,通过将实例属性指派为真或假,可以在单独的测试中重写类设置。
longMessage
-
该属性通过assert方法控制输出的最大长度,这些方法报告了故障的扩散。它默认为80个8个字符。Assert方法受该属性的影响是断言=()(包括所有委托给它的顺序比较方法)、断言()和断言多线等价()。
把maxDiff设置为None意味着没有最大的扩散长度。
maxDiff
测试框架可以使用以下方法来收集关于测试的信息:
-
返回由这个测试对象表示的测试的数量。对于TestCase实例,它总是为1
countTestCases
()-
退还测试结果类的一个实例,该实例应该用于这个测试用例类(如果没有为run()方法提供其他的结果实例)。
对于TestCase实例,这将始终是TestResult的一个实例;TestCase的子类应该在必要时重写这个。
defaultTestResult
()-
返回一个识别特定测试用例的字符串。这通常是测试方法的全名,包括模块和类名。
id
()-
返回对测试的描述,如果没有提供描述,则返回None。这个方法的默认实现返回test method的docstring的第一行,如果可用的话,或者没有。
shortDescription
()-
在tearDown()之后添加一个函数,以便清理测试期间使用的资源。函数将以相反的顺序调用它们被添加的顺序(LIFO)。它们被调用时,在添加的时候,会有任何参数和关键字参数被传递到add大扫除()中。
如果setUp()失败了,这意味着没有调用tearDown(),那么还会调用任何清除函数。
addCleanup
(function, *args, **kwargs)-
这个方法在tearDown()之后无条件地调用,或者在setUp()设置之后()设置一个异常。
它负责调用add大扫除()添加的所有清理功能。如果您需要在tearDown()之前调用清理函数,那么您可以自己调用doCleanups()。
doCleanups()每次清除清理函数堆栈中的方法,这样就可以随时调用它。
doCleanups
() -
- class
-
该类实现TestCase接口的一部分,允许测试运行者驱动测试,但不提供测试代码用来检查和报告错误的方法。这是用来使用遗留测试代码创建测试用例,允许它集成到基于unittest的测试框架中。
unittest.
FunctionTestCase
(testFunc, setUp=None, tearDown=None, description=None) 9.测试群
class unittest.TestSuite(test=())
该类代表了单个测试用例和测试套件的集合。该类提供了测试运行程序所需要的接口,允许它像其他测试用例一样运行。运行一个TestSuite实例与在套件中迭代一样,运行每个测试单独运行。
如果测试是给定的,那么它必须是单个测试用例或其他测试套件的迭代,这些测试套件最初将用于构建套件。还提供了额外的方法来将测试用例和套件添加到以后的集合中。
TestSuite对象的行为与TestCase对象很相似,只是它们实际上没有实现一个测试。相反,它们被用来将测试集合到应该一起运行的测试组中。还有一些附加的方法可以向TestSuite实例添加测试:
addTest(test)
添加一个TestCase或TestSuite到suite中
addTests(tests)
将TestCase和TestSuite实例的所有测试添加到这个测试套件中。
这就相当于迭代测试,为每个元素调用addTest()。
TestSuite与TestCase共享以下方法:
run(result)
运行与这个套件相关的测试,将结果收集到作为结果传递的测试结果对象中。注意,与testcase.run()不同,TestSuite.run()需要将结果对象传递进来。
debug()
运行与此套件相关的测试,而不收集结果。这允许将测试所提高的异常传播给调用者,并可用于支持调试器下的运行测试。
countTestCases()
返回由这个测试对象表示的测试的数量,包括所有单独的测试和子套件。
__iter__()
由TestSuite分组的测试总是通过迭代来访问。子类可以通过覆盖iter()延迟提供测试。请注意,这种方法可能在单个套件上调用了好几次(例如,在计算测试或比较相等的情况下),因此返回的测试必须与重复的迭代相同。
在TestSuite对象的典型用法中,run()方法由TestRunner调用,而不是由最终用户测试工具来调用。
10.导入并运行测试
class unittest.TestLoader
TestLoader类用来从类和模块创建测试套件。通常,不需要创建该类的实例;unittest模块提供了一个实例,可以作为unittest.defaultTestLoader共享。然而,使用子类或实例可以定制一些可配置的属性。
TestLoader对象有如下方法:
loadTestsFromTestCase
(testCaseClass)
返回testcase派生testCaseClass中包含的所有测试用例。
loadTestsFromModule
(module)
返回一个包含在给定模块中的所有测试用例的套件。这个方法搜索从TestCase派生出来的类,并为每个为类定义的测试方法创建一个类的实例。
注意:虽然使用testcase派生类的层次结构可以很方便地共享fixture和helper函数,但是在基类上定义不打算直接实例化的测试方法并不适合这种方法。然而,当这些fixture是不同的并且在子类中定义时,这样做是很有用的。
如果一个模块提供了loadtest函数,那么它将被调用来加载测试。这允许模块自定义测试加载。这是loadtest协议。
loadTestsFromName(name,module=None)
返回一个包含字符串说明符的所有测试用例。
specifier的名称是一个“点号”,它可以解析一个模块、一个测试用例类、一个测试用例类中的测试方法、一个TestSuite实例,或者一个可调用的对象,它返回一个TestCase或TestSuite实例。这些检查应用在这里列出的顺序;也就是说,在一个可能的测试用例类上的方法将被作为“测试用例类中的测试方法”而不是“可调用的对象”来获取。
例如,如果您有一个模块sampletest,它包含一个testcase衍生的类SampleTestCase,它有三个测试方法(testone()、test2()和test3()),这是specifier的sampletest。SampleTestCase将使这个方法返回一个将运行所有三个测试方法的套件。使用说明符的SampleTests.SampleTestCase。test2将使它返回一个测试套件,它只运行test2()测试方法。指定器可以引用尚未导入的模块和包;它们将作为副作用进口。
该方法可选择性地解析相对于给定模块的名称。
-
与loadTestsFromName()相似,但采用的是一系列名称而不是单个名称。返回值是一个测试套件,它支持为每个名称定义的所有测试。
loadTestsFromNames
(names, module=None) -
返回在testCaseClass中找到的方法名称的排序序列;这应该是TestCase的一个子类。
getTestCaseNames
(testCaseClass) -
从指定的开始目录中递归到子目录中查找所有的测试模块,并返回包含它们的TestSuite对象。只有匹配模式的测试文件才会被加载。(使用外壳样式匹配。)只加载可导入的模块名(即有效的Python标识符)。
所有的测试模块都必须从项目的顶层导入。如果起始目录不是顶级目录,那么顶层目录必须单独指定。
如果导入模块失败,例如由于语法错误,那么将记录为单个错误,并且发现将继续。
如果一个测试包名(带有init.py的目录)与模式匹配,那么这个包将会被检查为loadtest函数。如果存在这个问题,那么它将被调用装入器、测试和模式。
如果存在负载测试,那么discovery不会递归到包中,loadtest负责装入包中的所有测试。
该模式故意不作为加载器属性存储,以便包能够继续发现自己。topleveldir被保存,因此loadtest不需要将这个参数传递给loader.discover()。
startdir可以是一个虚线的模块名和一个目录。
.
discover
(start_dir, pattern='test*.py', top_level_dir=None) TestLoader的以下属性可以通过子类化或赋值来配置:
-
字符串给出方法名的前缀,这些名称将被解释为测试方法。默认值是“test”。
这将影响getTestCaseNames()和所有来自()方法的loadtestsall。
testMethodPrefix
-
当在getTestCaseNames()和所有loadtests()方法中对它们进行排序时,可以使用函数来比较方法名称。默认值是内置的cmp()函数;该属性也可以设置为None禁用sort。
sortTestMethodsUsing
-
可调用的对象,它从一个测试列表构造一个测试套件。不需要在产生的对象上使用任何方法。默认值是TestSuite类。
这将影响来自()方法的所有loadteststest。
suiteClass
- class
-
该类用于汇编关于哪些测试已经成功,哪些已经失败的信息。
TestResult对象存储一组测试的结果。TestCase和TestSuite类确保正确地记录结果;测试作者不需要担心记录测试的结果。
构建在unittest之上的测试框架可能需要访问TestResult对象,该对象是通过运行一组测试来生成报告目的;testrsult实例由testrsult.run()方法返回,用于此目的。
在检查运行一组测试的结果时,TestResult实例具有以下属性:
-
一个包含两个数组的TestCase实例和字符串的列表,其中包含了格式化的traceback。每个元组代表一个测试,它引发了一个意外的异常。
版本2中的更改:包含格式化的traceback,而不是sys.exc info()结果。
errors
-
一个包含两个数组的TestCase实例和字符串的列表,其中包含了格式化的traceback。每个元组都代表一个测试,其中使用testcase.assert()方法显式地表示失败。
版本2中的更改:包含格式化的traceback,而不是sys.exc info()结果。
failures
-
一个包含两个数组的TestCase实例和字符串的列表,其中包含了跳过测试的原因。
skipped
-
一个包含两个数组的TestCase实例和字符串的列表,其中包含了格式化的traceback。每个元组表示测试用例的预期失败。
expectedFailures
-
包含了被标记为预期失败的TestCase实例的列表,但是成功了。
unexpectedSuccesses
-
当测试的执行应该在stop()停止时设置为True。
shouldStop
-
所有到目前为止运行的测试的数量
testsRun
-
如果设为true,sys。stdout和系统。stderr将在被调用的最星()和stopTest()之间进行缓冲。收集的输出只会在真实的系统中得到响应。stdout和系统。如果测试失败或错误,stderr。任何输出都附加到故障/错误消息。
buffer
-
如果设置为true stop()会在第一次失败或错误中调用,停止测试运行。
failfast
-
返回True
如果所有的测试到目前位置都passed, 否则返回False
.
wasSuccessful
()-
这个方法可以被调用来表示正在运行的测试集应该通过将shouldStopattribute设置为True来中止。TestRunner对象应该尊重这面旗帜,并返回不运行任何额外的测试。
例如,当用户从键盘发出一个中断时,TextTestRunner类将使用该特性来停止测试框架。提供TestRunner实现的交互式工具可以以类似的方式使用它。
stop
()TestResult类的下列方法用于维护内部数据结构,并且可以在子类中扩展以支持额外的报告需求。这对于在运行测试时支持交互式报告的工具尤其有用。
-
测试用例将要执行时调用
startTest
(test)-
无论结果如何,在测试用例执行之后都要执行
stopTest
(test)-
在任何测试执行之前调用一次
startTestRun
()-
所有测试执行完后调用一次
stopTestRun
()-
当测试用例测试引发意外异常时调用。err是sys.exc info()返回的表单元组:(类型、值、回溯)。
缺省实现将tuple(test、formattederr)附加到实例的errors属性,其中formattederr是一种从错误中派生出来的格式化回溯。
addError
(test, err)-
当测试用例测试显示失败时调用。err是sys.exc info()返回的表单元组:(类型、值、回溯)。
缺省实现将tuple(test、formattederr)附加到实例的故障属性中,其中formattederr是一种从错误中派生出来的格式化traceback。
addFailure
(test, err)-
当测试用例测试成功时调用。
默认的实现什么都不做。
addSuccess
(test)-
在跳过测试用例测试时调用。原因是测试给出了跳过的原因。
默认的实现将一个元组(测试、推理)附加到实例的跳过属性。
addSkip
(test, reason)-
当测试用例测试失败时调用,但是被标记为预期失败()decorator。
默认的实现将一个tuple(test,formattederr)附加到实例的期望失败属性中,其中formattederr是一个从错误中派生出来的格式化的回溯。
addExpectedFailure
(test, err)-
当测试用例测试用预期失败()decorator标记时调用,但是成功了。
默认的实现将测试附加到实例的不可预测的成功属性。
addUnexpectedSuccess
(test) -
unittest.
TestResult
- class
-
TextTestRunner使用的TestResult的具体实现。
新版本7:这个类以前叫做TextTestResult。旧名称仍然作为别名存在,但已被弃用。
unittest.
TextTestResult
(stream, descriptions, verbosity) -
TestLoader类的实例打算被共享。如果不需要对TestLoader进行定制,那么可以使用这个实例,而不是重复创建新实例。
unittest.
defaultTestLoader
- class
-
一个基本的测试运行器实现,它打印出标准错误的结果。它有一些可配置参数,但本质上非常简单。运行测试套件的图形化应用程序应该提供备选实现。
-
这个方法返回run()所使用的TestResult实例。它不打算直接调用,但是可以在子类中重写以提供定制的TestResult。
makeResult()实例化在TextTestRunner构造函数中作为resultclass参数传递的类或callable。如果没有提供resultclass,它将默认为TextTestResult。结果类用以下参数实例化:
stream, descriptions, verbosity
_makeResult
() -
unittest.
TextTestRunner
(stream=sys.stderr, descriptions=True, verbosity=1, failfast=False, buffer=False, resultclass=None) unittest.
main
([module[, defaultTest[, argv[, testRunner[, testLoader[, exit[, verbosity[, failfast[, catchbreak[, buffer]]]]]]]]]])
一个命令行程序,它从模块加载一组测试并运行它们;这主要是为了让测试模块方便地执行。这个函数最简单的用法是在测试脚本的末尾包含以下行:
if __name__ == '__main__': unittest.main()
您可以通过传递冗长的参数来运行带有更详细信息的测试:
if __name__ == '__main__': unittest.main(verbosity=2)
如果没有通过argv指定测试名称,则默认的参数是运行测试的名称。如果没有指定或None,并且没有通过argv提供测试名称,则运行在模块中发现的所有测试。
argv参数可以是传递给程序的选项列表,第一个元素是程序名。如果没有指定,或者没有,系统的值。argv。
testRunner参数可以是一个测试运行器类,也可以是已经创建的实例。默认情况下,main调用sys.exit()带有退出代码,指示测试运行成功或失败。
testLoader参数必须是一个testLoader实例,并且默认为defaultTestLoader。
主要支持通过传入参数出口=False来从交互式解释器中使用。这样就可以在不调用sys.exit()的情况下显示输出结果。
>>> from unittest import main>>> main(module='test_module', exit=False)
故障快速、中断和缓冲区参数与相同名称的命令行选项具有相同的效果。
调用main实际上返回了TestProgram类的一个实例。这会将测试的结果存储为result属性。
11.load_tests 协议
模块或包可以在正常的测试运行过程中定制测试的加载方式,或者通过实现一个名为loadtest的功能来测试发现。
如果一个测试模块定义load_tests将被称为TestLoader.loadTestsFromModule()使用以下参数:
load_tests(loader, standard_tests, None)
它应该返回一个TestSuite。
加载器是加载的TestLoader的实例。标准测试是默认从模块加载的测试。测试模块通常只希望在标准的测试集中添加或删除测试,这是很常见的。第三个参数用于装载包作为测试发现的一部分。
一个典型的loadtest函数,它从一个特定的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将会被检查以进行loadtest。
备注:
默认的模式是“test.py”。这匹配所有以“test”开头的Python文件,但不匹配任何测试目录。
像“test”这样的模式将会匹配测试包和模块。
如果包的__init__.py定义了loadtest,它将被调用,而发现不会继续存在于包中。用以下参数调用loadtest:
load_tests(loader, standard_tests, pattern)
这应该返回一个TestSuite,它代表了来自包的所有测试。(标准测试只包含从init.py中收集的测试。)
因为模式被传递到loadtest中,所以包可以自由地继续(并可能修改)测试发现。一个测试包的“不做”loadtest函数会是这样的:
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
12.类和模块框架
类和模块级的fixture是在TestSuite中实现的。当测试套件从一个新类中遇到一个测试时,从先前的类(如果有的话)调用tearDownClass(),然后从新类中调用setUpClass()。
类似地,如果一个测试来自于以前测试的另一个模块,则运行前一个模块中的tearDownModule,然后是来自新模块的setUpModule。
在所有的测试运行之后,最终的tearDownClass和tearDownModule都将运行。
请注意,共享的fixture不能很好地处理诸如测试并行化之类的潜在特性,它们会破坏测试隔离。它们应该小心使用。
unittest测试加载器创建的测试的默认顺序是将来自相同模块和类的所有测试分组在一起。这将会导致setUpClass/setUpModule(etc)在每个类和模块中被调用一次。如果您对顺序进行随机化,那么来自不同模块和类的测试彼此相邻,那么在一次测试运行中,这些共享的fixture函数可能会被多次调用。
共享的fixture并不是用来处理非标准排序的套件。对于不希望支持共享fixture的框架来说,仍然存在一个BaseTestSuite。
如果在共享的fixture功能中有任何异常,那么测试将被报告为一个错误。因为没有对应的测试实例,所以创建了ErrorHolder对象(与TestCase有相同的接口)来表示错误。如果你只是使用标准的unittest测试者,那么这个细节并不重要,但是如果你是一个框架的作者,它可能是相关的。
12.1setUpClass 和tearDownClass
这些必须作为类方法实现:
import unittestclass 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异常,那么该类将被报告为被跳过而不是作为一个错误。
12.2 setUpModule和tearDownModule
这些应该作为函数来实现:
def setUpModule(): createConnection()def tearDownModule(): closeConnection()
如果在setUpModule中提出了一个异常,那么模块中的所有测试都不会运行,而tearDownModule将不会运行。如果异常是一个SkipTest异常,那么这个模块将被报告为被跳过而不是作为一个错误。
13.信号处理
-c/-catch命令行选项到unittest,与unittest.main()的catch break参数一起,在测试运行期间提供更友好的control-C处理。有了catch中断行为,control-C将允许当前运行的测试完成,并且测试运行将结束并报告所有的结果。第二个control-c将以通常的方式触发一个键盘中断。
control-c处理信号处理程序试图保持与安装它们自己的信号的代码或测试兼容。信号情报处理程序。如果unittest处理器被调用,但它不是已安装的信号。SIGINT处理程序,也就是说,它已经被系统所取代,并被委托给它,然后它调用默认的处理程序。这通常是代码中所期望的行为,它将替换已安装的处理程序和委托给它。对于需要unittest control-c处理的单独测试,可以使用removeHandler()decorator。
框架作者有一些实用功能,可以在测试框架内启用控制c处理功能
-
安装control-c handler. 当
signal.SIGINT
被接收时 (通常提示用户按 control-c) 所有结果都会调用
unittest.
installHandler
() -
注册一个TestResult对象用于控制c处理。注册一个结果存储了一个弱引用,所以它不会阻止结果被垃圾收集。
如果没有启用control-c处理,注册一个TestResult对象没有副作用,因此测试框架可以无条件地注册它们创建的所有结果,而不管是否启用了处理。
unittest.
registerResult
(result) -
删除一个注册的结果。一旦一个结果被删除,那么stop()将不再在那个结果对象上被调用,以响应control-c。
unittest.
removeResult
(result) -
如果没有参数调用,该函数如果已安装完毕,则删除control-c处理程序。这个函数也可以用作测试修饰符,以便在执行测试时临时删除处理程序:
@unittest.removeHandlerdef test_signal_handling(self):
unittest.
removeHandler
(function=None)