在线文档教程

test

测试 - Python的回归测试包

注意

test软件包仅供Python内部使用。这是为Python的核心开发人员的利益记录的。任何在Python标准库之外使用这个包都是不鼓励的,因为这里提到的代码可以在Python的发行版之间改变或删除,恕不另行通知。

test软件包包含所有Python的回归测试以及模块test.test_supporttest.regrtesttest.test_support用于在test.regrtest推动测试套件的同时增强您的测试。

test软件包中名称以开头的每个模块test_都是特定模块或功能的测试套件。所有新的测试应该使用unittestdoctest模块编写。一些较旧的测试是使用“传统”测试样式来编写的,该样式比较输出的打印结果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,-largefiletest.regrtest使用除资源audiolargefile资源外的所有资源运行。有关所有资源和更多命令行选项的列表,请运行python -m test.regrtest -h

执行回归测试的其他一些方法取决于正在执行测试的平台。在Unix上,您可以在构建Python的顶级目录中运行make test。在Windows上,从您的目录执行rt.batPCBuild将运行所有的回归测试。

test.test_support - 用于测试的实用程序函数

注意

test.test_support模块已被重命名为test.supportPython 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如果资源不可用。msgResourceDenied如果它被引发的参数。始终返回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)作为位置参数。如果提供了一个或多个过滤器,或者如果可选关键字参数quietFalse,它会检查以确保警告符合预期:每个指定的过滤器必须至少匹配由所附代码引发的警告之一或者测试失败,并且如果发现任何与指定过滤器不匹配的警告,则测试失败。要禁用这些检查中的第一项,请将安静设置为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(),原始模块不受此操作的影响。

freshsys.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版本中的新功能。