企业软件需要测试,如同建筑物需要消防和安全检查。如果你知道某些电气状况或结构问题可能导致灾难,不会只寻找一次,而是会反复寻找。同样,如果你想防止应用软件中的某些问题或状况,为此编写测试可以确保它们永远不会进入到生产环境。
对于像Python这样的动态语言来说,测试尤为重要。如果是动态语言,大批的错误仅在运行时出现。可靠的测试套件有助于揪出这些问题,为继承代码库的人提供同样揪出问题的方法。
默认情况下,Python随带自己的单元测试框架,该框架既实用又广泛使用。但还有另外诸多方法,每种方法对于如何构建和维护单元测试有各自的理念。下面介绍了默认方法unittest以及三种重要的替代方法。
unittest和doctest
unittest是Python标准库附带的默认测试框架,用于为Python本身创建测试套件。 unittest不像一些第三方测试框架那样覆盖广泛,它本来就不是要这样——它提供了足以为大多数项目编写可靠的单元测试的功能。用过JUnit测试框架的Java开发人员应该熟悉unittest。
要创建测试套件,你要创建从unittest.TestCase派生的Python类,测试是那些类中的函数。测试可能是简单的相等或不相等断言,也可能是较为复杂的。比如说,assertRaises测试确保为特定测试引发特定异常。
测试可以分组为单个文件,也可以跨多个文件隔开、自动发现然后加以执行。你还可以为每个测试组提供fixture(安装和拆卸例程),指定在特定条件下跳过的测试,并控制测试的执行行为。
使用unittest的优点是它众所周知。就因为其他Python程序员非常熟悉测试套件的编写方式,就很难搞错unittest。
doctest也是Python标准库附带的,是补充模块。Doctest寻找Python文件中格式类似Python交互式会话的注释,并尝试运行这些注释中包含的命令以查看结果是否匹配。这样一来,可以验证函数的文档字符串中的示例输出以及函数的行为。
请注意,doctest最适合输入输出在控制台中一目了然的简单函数的测试,以及不需要大量安装或拆卸即可生成结果的测试。如果你尝试对复杂函数执行doctest,最终可能得到太过笨拙而没有用处的doctest示例。
pytest
pytest项目可以完全替换或增强unittest。Pytest运用了一种不同的理念来测试编写,从而使开发人员无需大量的脚手架代码,即可快速为项目实施小型测试套件。随着项目不断扩大,pytest可以扩大规模进行匹配,允许更多的测试功能可以逐渐添加上去。
pytest测试一开始是遵循模块中某种命名约定的紧凑函数,而不是现有测试类型类的子类。通过从命令行在模块上运行pytest或在代码内调用pytest来调用测试。你可以创建pytest fixture来安装和拆卸测试条件,并根据需要对这些fixutre规定宽泛或狭窄的范围(比如从整个测试会话范围到仅函数范围)。
你可以添加的选项数量众多且功能强大。成百上千个pytest插件让你可以将测试与许多第三方服务和操作集成起来。最后,unittest和nose测试套件也可以作为测试过程的一部分来运行,那样你可以将pytest与现有套件集成起来,不必丢弃它们、从头开始。
nose和nose2
nose及后续者nose2扩展了用unittest编写的测试,使它们更易于运行。nose本身不再加以维护;nose2延续这个项目,与Python 3兼容,功能上有一些变化,但基本理念一样。我们在这里主要介绍nose2。
nose2在两个主要方面有别于unittest:它拥有插件架构,并使用.ini样式的配置文件来控制测试如何运行。默认情况下,提供并启用了许多nose2插件。.ini文件包括诸多设置,比如测试运行期间探查哪些目录、使用哪些插件。因此,可以对一组具有罕见行为的nose2测试进行精确的脚本编写,可以毫不费力地重复使用。
nose2运行时,它查找以名称test开头的模块,还有从unittest.TestCase派生的任何类,因此它可以运行通过pytest或unittest范式设计的测试。当模块以独立的方式加以执行时,nas2测试也可以配置成运行(unittest和pytest也可以做到这样)。
请注意,nose2可能不是你首次尝试测试Python应用程序的优先选择,因为它假设你在创建测试方面有一定的经验。你需要先试一试unittest。
behave
behave是使用“行为驱动开发”(BDD)范式的许多面向Python的测试框架之一。你可以用简单的英语“功能文件”描述测试的预期行为,并将测试本身写在另一个文件中,然后执行behave,观察测试运行情况,通过英语描述提供了注释。
与通常需要先编写代码的测试编写方法相比,这可能显得更死板僵硬。但是BDD方法旨在使测试更容易为编写测试的开发人员进行推理,并且使其他人(包括最终用户和其他开发人员)更容易理解测试的用途和原因。behave非常适合必须谨小慎微的项目。
behave让你可以通过指定能添加到功能文件中个别案例的“标签”或元数据,从命令行选择性地运行测试。还可以定义精细化的逐步行为,比如安装和拆卸程序。behave测试还可以与Django和Flask Web框架集成起来。
还有其他几种面向Python的BDD框架,比如Lettuce和Radish,但behave是使用最广泛的框架之一。