test
测试 - Python的回归测试包
注意
test
软件包仅供Python内部使用。这是为Python的核心开发人员的利益记录的。任何在Python标准库之外使用这个包都是不鼓励的,因为这里提到的代码可以在Python的发行版之间改变或删除,恕不另行通知。
test
软件包包含所有Python的回归测试以及模块test.test_support
和test.regrtest
。test.test_support
用于在test.regrtest
推动测试套件的同时增强您的测试。
test
软件包中名称以开头的每个模块test_
都是特定模块或功能的测试套件。所有新的测试应该使用unittest
或doctest
模块编写。一些较旧的测试是使用“传统”测试样式来编写的,该样式比较输出的打印结果sys.stdout
; 这种测试风格被认为已被弃用。
另请参阅
Module
unittest
编写PyUnit回归测试。 Module
doctest
嵌入在文档字符串中的测试。
1.编写测试包的单元测试
最好使用unittest
模块的测试遵循一些准则。一种是通过启动测试模块来命名测试模块,并以被测模块test_
的名称结束测试模块。测试模块中的测试方法应该以测试方法test_
的描述开始并结束。这是必需的,以便测试驱动程序将这些方法识别为测试方法。此外,该方法不应包含任何文档字符串。# Tests function returns only True or False
应该使用评论(如)为测试方法提供文档。这样做是因为文档字符串如果存在,就会被打印出来,因此没有说明正在运行的测试。
通常使用基本的样板文件:
import unittest
from test import test_support
class MyTestCase1(unittest.TestCase):
# Only use setUp() and tearDown() if necessary
def setUp(self):
... code to execute in preparation for tests ...
def tearDown(self):
... code to execute to clean up after tests ...
def test_feature_one(self):
# Test feature one.
... testing code ...
def test_feature_two(self):
# Test feature two.
... testing code ...
... more test methods ...
class MyTestCase2(unittest.TestCase):
... same structure as MyTestCase1 ...
... more test classes ...
def test_main():
test_support.run_unittest(MyTestCase1,
MyTestCase2,
... list other tests ...
)
if __name__ == '__main__':
test_main()
这个样板代码允许测试套件以test.regrtest
脚本的形式运行。
回归测试的目标是试图破解代码。这导致了一些指导方针要遵循:
- 测试套件应该执行所有的类,函数和常量。这不仅包括要呈现给外部世界的外部API,还包括“私人”代码。
- Whitebox测试(在测试写入时检查正在测试的代码)是首选。Blackbox测试(仅测试已发布的用户界面)不够完整,无法确保所有边界和边缘案例都经过测试。
- 确保所有可能的值都经过测试,包括无效值。这确保不仅所有有效值都可以接受,而且不正确的值也可以正确处理。
- 尽可能多地排除代码路径。测试发生分支的位置,从而定制输入以确保通过代码获取许多不同的路径。
- 为测试代码发现的任何错误添加显式测试。这将确保如果将来代码被更改,错误不会再次出现。
- 确保在测试后清理(如关闭并删除所有临时文件)。
- 如果测试取决于操作系统的特定条件,则在尝试进行测试之前验证已存在的条件。
- 尽可能少地导入模块,尽快完成。这样可以最大限度地减少测试的外部依赖性,并最大限度地减少导入模块副作用时可能出现的异常行为。
- 尝试最大化代码重用。有时候,测试会随着使用什么类型的输入而变化。通过用指定输入的类继承基本测试类来最小化代码重复:
class TestFuncAcceptsSequences(unittest.TestCase):func = mySuperWhammyFunction def test_func(self):self.func(self.arg)class AcceptLists(TestFuncAcceptsSequences):arg = 1,2,3级AcceptStrings(TestFuncAcceptsSequences):arg ='abc'class AcceptTuples(TestFuncAcceptsSequences):arg =(1,2,3)
另请参阅
测试驱动开发Kent Beck在编写代码之前编写测试的书。
2.使用命令行界面运行测试
该test.regrtest
模块可以作为脚本运行,以驱动Python的回归测试套件,这要归功于以下-m
选项:python -m test.regrtest
。自行运行脚本会自动开始运行test
包中的所有回归测试。它通过查找名称以开头的包中的所有模块test_
,导入它们并执行该函数(test_main()
如果存在)来完成此操作。要执行的测试名称也可以传递给脚本。指定单一回归测试(python -m test.regrtest test_spam
)将使输出最小化,并且只打印测试是通过还是失败,从而最小化输出。
test.regrtest
直接运行允许测试使用哪些资源可供设置。您可以通过使用-u
命令行选项来完成此操作。指定all
该-u
选项的值将启用所有可能的资源:python -m test.regrtest -uall
。如果只需要一种资源(更常见的情况),则可能会列出不需要的以逗号分隔的资源列表all
。命令python -m test.regrtest -uall,-audio,-largefile
将test.regrtest
使用除资源audio
和largefile
资源外的所有资源运行。有关所有资源和更多命令行选项的列表,请运行python -m test.regrtest -h
。
执行回归测试的其他一些方法取决于正在执行测试的平台。在Unix上,您可以在构建Python的顶级目录中运行make test
。在Windows上,从您的目录执行rt.bat
PCBuild
将运行所有的回归测试。
test.test_support - 用于测试的实用程序函数
注意
test.test_support
模块已被重命名为test.support
Python 3.x.
test.test_support
模块为Python的回归测试提供支持。
该模块定义了以下例外情况:
exception test.test_support.TestFailed
测试失败时会引发异常。这不利于unittest
基于测试和unittest.TestCase
断言的方法。
exception test.test_support.ResourceDenied
子类unittest.SkipTest
。当资源(如网络连接)不可用时引发。由requires()
功能引发。
test.test_support
模块定义了以下常量:
test.test_support.verbose
True
当详细
输出被启用时。当需要关于运行测试的更多详细
信息时应该检查。详细
由test.regrtest
...设置。
test.test_support.have_unicode
True
当Unicode支持可用时。
test.test_support.is_jython
True
如果正在运行的解释器是Jython。
test.test_support.TESTFN
设置为可安全使用的名称作为临时文件的名称。任何创建的临时文件应该关闭并取消链接(删除)。
test.test_support
模块定义了以下功能:
test.test_support.forget(module_name)
删除名为module_name
的模块,sys.modules
并删除模块的所有字节编译文件。
test.test_support.is_resource_enabled(resource)
True
如果资源
已启用且可用,则返回。可用资源
列表仅在test.regrtest
执行测试时设置。
test.test_support.requires(resource[, msg])
提高ResourceDenied
如果资源
不可用。msg
是ResourceDenied
如果它被引发的参数。始终返回True
如果调用由它的功能__name__
是'__main__'
。在执行测试时使用test.regrtest
。
test.test_support.findfile(filename)
将路径返回到名为filename的文件
。如果找不到匹配,则返回文件名
。这不等于失败,因为它可能是文件的路径。
test.test_support.run_unittest(*classes)
执行unittest.TestCase
传递给该函数的子类。该函数扫描以前缀开头的方法的类test_
并单独执行测试。
将字符串作为参数传递也是合法的; 这些应该是关键sys.modules
。每个关联的模块将被扫描unittest.TestLoader.loadTestsFromModule()
。这通常在以下test_main()
函数中看到:
def test_main():
test_support.run_unittest(__name__)
这将运行在命名模块中定义的所有测试。
test.test_support.check_warnings(*filters, quiet=True)
这是一个便捷的包装warnings.catch_warnings()
,可以更容易地测试警告是否正确引发。这大致等同于warnings.catch_warnings(record=True)
使用warnings.simplefilter()
设置来调用always
并使用选项来自动验证记录的结果。
check_warnings
接受表单的2元组("message regexp", WarningCategory)
作为位置参数。如果提供了一个或多个过滤器
,或者如果可选关键字参数quiet
是False
,它会检查以确保警告符合预期:每个指定的过滤器
必须至少匹配由所附代码引发的警告之一或者测试失败,并且如果发现任何与指定过滤器
不匹配的警告,则测试失败。要禁用这些检查中的第一项,请将安静
设置为True
。
如果没有指定参数,则默认为:
check_warnings(("", Warning), quiet=True)
在这种情况下,所有警告都会被捕获,并且不会引发错误。
在进入上下文管理器时,WarningRecorder
返回一个实例。潜在的警告列表来自catch_warnings()
于记录器对象的warnings
属性。为了方便起见,还可以通过记录器对象直接访问表示最近警告的对象的属性(请参见下面的示例)。如果没有发出警告,则表示警告的对象的任何属性将返回None
。
记录器对象也有一个reset()
方法,清除警告列表。
上下文管理器被设计为像这样使用:
with check_warnings(("assertion is always true", SyntaxWarning),
("", UserWarning)):
exec('assert(False, "Hey!")')
warnings.warn(UserWarning("Hide me!"))
在这种情况下,如果没有提出任何警告或者提出了其他警告,check_warnings()
则会引发错误。
当测试需要更深入地看待警告时,而不是仅仅检查它们是否发生,可以使用类似这样的代码:
with check_warnings(quiet=True) as w:
warnings.warn("foo")
assert str(w.args[0]) == "foo"
warnings.warn("bar")
assert str(w.args[0]) == "bar"
assert str(w.warnings[0].args[0]) == "foo"
assert str(w.warnings[1].args[0]) == "bar"
w.reset()
assert len(w.warnings) == 0
这里所有警告都会被捕获,并且测试代码会直接测试捕获的警告。
2.6版本中的新功能。
在版本2.7中更改:新的可选参数过滤器
和安静
。
test.test_support.check_py3k_warnings(*filters, quiet=False)
类似于check_warnings()
Python 3的兼容性警告。如果sys.py3kwarning == 1
它检查警告是否有效提高。如果sys.py3kwarning == 0
它检查没有发出警告。它接受表单的2元组("message regexp", WarningCategory)
作为位置参数。当可选关键字参数安静的
是True
,如果能够过滤掉没有它不会失败。没有参数,它默认为:
check_py3k_warnings(("", DeprecationWarning), quiet=False)
2.7版本的新功能。
test.test_support.captured_stdout()
这是一个with
使用StringIO.StringIO
对象作为sys.stdout 运行语句体的上下文管理器。该对象可以使用语句的as
子句进行检索with
。
使用示例:
with captured_stdout() as s:
print "hello"
assert s.getvalue() == "hello\n"
2.6版本中的新功能。
test.test_support.import_module(name, deprecated=False)
该函数导入并返回指定的模块。与正常导入不同,unittest.SkipTest
如果模块无法导入,此功能将会提升。
如果模块和封装弃用
消息这个导入期间抑制弃用
是True
。
2.7版本的新功能。
test.test_support.import_fresh_module(name, fresh=(), blocked=(), deprecated=False)
此函数通过sys.modules
在导入之前删除命名模块来导入并返回指定Python模块的新副本。请注意,与此不同reload()
,原始模块不受此操作的影响。
fresh
是sys.modules
在进行导入之前从缓存中删除的附加模块名称的迭代。
被阻止的
是0
在导入期间在模块高速缓存中替换的模块名称的迭代,以确保尝试导入它们ImportError
。
在开始导入之前保存已命名的模块以及在新鲜
和已阻止
参数中命名的所有模块,并sys.modules
在新导入完成时重新插入。
如果模块和封装弃用
消息这个导入期间抑制弃用
是True
。
unittest.SkipTest
如果无法导入已命名的模块,则会引发此功能。
使用示例:
# Get copies of the warnings module for testing without
# affecting the version being used by the rest of the test suite
# One copy uses the C implementation, the other is forced to use
# the pure Python fallback implementation
py_warnings = import_fresh_module('warnings', blocked=['_warnings'])
c_warnings = import_fresh_module('warnings', fresh=['_warnings'])
2.7版本的新功能。
该test.test_support
模块定义了以下类:
class test.test_support.TransientResource(exc[, **kwargs])
实例是在引发ResourceDenied
指定的异常类型时引发的上下文管理器。任何关键字参数都被视为属性/值对,以便与with
语句中引发的任何异常进行比较。只有在所有对匹配都正确的情况下才会ResourceDenied
引发异常。
2.6版本中的新功能。
class test.test_support.EnvironmentVarGuard
用于临时设置或取消设置环境变量的类。实例可以用作上下文管理器并具有用于查询/修改底层的完整字典界面os.environ
。从上下文管理器退出后,通过此实例完成的对环境变量的所有更改都将回滚。
2.6版本中的新功能。
在版本2.7中更改:添加了字典界面。
EnvironmentVarGuard.set(envvar, value)
暂时将环境变量设置envvar
为的值value
。
EnvironmentVarGuard.unset(envvar)
暂时取消设置环境变量envvar
。
class test.test_support.WarningsRecorder
用于记录单元测试警告的类。有关check_warnings()
更多详细信息,请参阅上述文档
2.6版本中的新功能。