APP下载

基于Python的测试驱动开发框架

2018-09-17朱道雨

科教导刊·电子版 2018年20期

朱道雨

摘 要 本文首先介绍了测试驱动开发,继而介绍了测试模式,描述了测试驱动开发的优势、一般步骤、测试的原则和对一般开发人员的要求,最后比较详细地介绍了几种基于Python的测试框架。

关键词 测试驱动开发 Python 测试框架

中图分类号:TP3 文献标识码:A

1测试驱动开发介绍

测试驱动开发(TDD)是一种不同于传统开发流程的新型的开发方法,采取了很小的增量式开发方式,强调测试在软件开发过程中的作用。TDD是一种编码之前进行单元测试的软件开发思想。TDD先行定义了需求,扩大测试覆盖率,从而推进整个开发过程。其编写的代码简洁、健壮且高质量,加快软件开发。

2测试模式介绍

针对软件开发典型的瀑布模型,其是一种带有部分反馈的自上而下的开发模式,对文档支持要求高。该模型按照阶段划分了检查点,最终产品只能在后期才能看到最终结果,测试阶段一般占一半时间。软件测试和软件开发过程一样遵循软件工程原理,下面以V模型和X模式为例对测试与开发之间的关系进行说明。

2.1 V测试模型

V模型和瀑布开发模型一样,存在需求分析、概要设计、详细设计、代码编码等阶段,这些过程都需考虑对应的测试工作,同时设计测试用例、编制测试计划。V模型明确标明了测试的不同级别,清楚地描述了测试阶段和开发过程期间各阶段的对应的关系。需求分析产生的错误直到验收测试才能发现是其最大的局限性。

2.2 X测试模型

图1:X模型图

如图,X模型更详细地描述了详细设计和编码阶段的开发行为,分离单程序片段的编码和测试,直到集成为可执行程序,然后测试这些可执行程序。已通过集成测试的成品既可封装并提交给用户,也可作为更大规模集成的一部分,针对多程序片段,分离编码和测试,并定义了探索性测试,强调单元测试和集成测试的重要性。

3 TDD的优势以及一般步骤

3.1 TDD优势

TDD相较于传统的结构化开发过程方法,具有以下优势:

3.1.1更快更好地迎接需求变化

根据客户需求编写测试用例,关注用户反馈和以使用者的角度对功能的过程和接口进行设计,可及时响应需求变更,更符合后期开发的需求。同时覆盖完全的单元测试,提高了代码的可靠性。

3.1.2明显地缩短了设计决策的反馈循环

基于易测试和测试独立性的要求,更多地依赖于接口,通过实现松耦合的设计,提高系统的可扩展性和抗变性;同时对其功能的分解、使用过程、接口都进行了设计。

3.1.3降低了后续测试的成本

TDD先考虑代码的使用需求――功能、过程、接口等,再确认需求是无歧义的、可验证的。首先将测试提到编码之前并频繁地运行所有测试,尽早地发现或避免错误,不断地重构代码并消除重复设计,提高代码的重用,极大地提高代码的健壮性。

3.1.4提供持续的回归测试

TDD能帮助开发人员持续地跟踪软件生命周期内的全部状态,并快速地反馈开发人员,使开发人员无需过分担心不可预知的异常并大胆地实施重构。

3.1.5提供合格的文档

TDD所产生的单元测试代码是最完美的開发者文档,含有API如何使用的信息,同时与最新的代码保持同步。

3.2 TDD的一般步骤

(1)明确当前主要完成的功能,并形成电子或者书面的记录表单;

(2)快速地编写此功能的测试用例;

(3)运行测试,发现新增的测试不能通过测试;

(4)改动测试程序,尽快让测试程序通过运行

(5)重构已完成的代码,消除重复设计,优化程序结构,并保证测试通过

(6)循环完成所有功能。

3.3测试原则

(1)测试隔离,不同代码的测试相互隔离,对单块代码的测试应只考虑该代码的测试,

(2)测试列表,在软件开发的任意阶段,添加新功能需求时,需将相关功能点添加到测试列表中,不断地完成测试用例,并重构。

(3)测试驱动,在完成代码类、功能设计前,首先编制测试代码,考虑如何使用与测试,继而设计编码。

(4)测试与断言优先,在编写代码之前编写测试,在编制代码过程中,首先编写断言语句,再编写辅助语句。

(5)可测试性,代码设计过程必须具有较强的可测试性,有助于提高代码的内聚性和复用。

(6)及时重构,无论是功能代码还是测试代码,对结构不合理、重复的代码,都要进行及时的重构。

4测试框架

4.1 unittest测试框架

该测试框架中最核心的概念为:test case,test suite,test runner,text fixture。unittest提供了TestCase基类来构造单元测试用例,在构建测试用例的时候,使用setUp方法初始化测试环境,tearDown方法执行扫尾结束工作并还原测试环境,这类似于上下文管理器,setUp和tearDown每次必须运行一次(如图2)。

图2:测试流程图

TestLoader用来加载TestCase、TestSuite,可使用LoadTestsForm方法,创建测试实例,继而add到TestSuite中,返回一个TestSuite实例。使用TextTestRunner执行测试用例,其中,测试结果保存到Result中,包括运行的用例数量、成功与失败信息。Fixture完成测试环境的搭建和销毁。

通过命令行或者main函数来启动单元测试,main会调用run来执行,当Runner执行时,将执行结果输出到控制台或文件,通过设置verbosity参数控制执行结果的输出。unittest框架比较笨重且难以扩展,必须在TestCase子类中编写所有的单元测试和断言方法,必须为测试活动建立测试套件。

4.2 doctest测试

doctest测试框架在文档字符串(docstring)内嵌注释,这些注释将各单元模块的期望结果予以表达,字符串如同交互式shell会话搜索Python代码,继而尝试执行并验证结果。测试用例的位置必须放在整个模块文件的开始部分或紧接声明语句的下一行。设置verbose 参数用于控制是否输出详细信息,默认不输出任何东西,除非测试失败。

当不带任何参数运行 test_basic.py 时。将test_basic 导入到脚本的命名空间中,可导入其他希望要测试的模块。testmod函数去遍历模块本身、模块函数及其所有文档字符串,以找出所有类似交互式 shell 会话的内容。

doctest 在解析显式会话时,将空行作为会话结束来处理。可利用文档字符串自定义的函数来解决此问题。一方面由于文档字符串毕竟是字符串换码,所以要注意\n这样的序列被扩展。另一方面由 doctest处理的文档字符串可能会在其内部包含回溯。

4.3 nose 系列

由于扩展自unittest的扩展,nose 也支持类似于 setUp、setUpClass、setUpModule 的测试环境创建方式,所以python的测试更加简单。nose自动发现测试代码并执行,nose提供了大量的插件,比如测试输出的xUnitcompatible,覆盖报表等等。

路径、模块(文件)、类、函数的名字若匹配上testMatch,那就会被认为是一个用例,另外所有 unittest.TestCase 的子类都会被当做测试用例。nose主要检查一个测试用例的文件夹,否则会忽略此文件路径。显式地避免某个对象被当做测试用例的方法是:给其或其容器添加一个 _test_ 属性,并且运算结果不为 True,只要 bool(_test_) == False 即可。

nose可不使用特定的格式、不需要一个类容器,甚至不需要 import,但nose测试用例的命名仍需以 test_开头。

4.4 pytest

作为unittest的替代工具,pytest是一个语法简单且功能丰富灵活的测试框架。相比unittest,实现相同的测试功能,pytest更简洁高效;支持简单的单元测试和复杂的功能测试,支持参数化,支持重复执行失败的case,支持运行由nose、unittest编写的测试case。

pytest 创建测试环境(fixture)的方式,通过显式指定scope参数来选择装饰器。一个fixture 函数的类型一旦定义即确定,对于 scope=function 的 fixture 函數会在测试用例的前后分别调用 setup/teardown。测试用例的参数只负责引用具体的对象,并不关心作用域;同时setup/teardown 语法与 unittest 的兼容性不如 nose 高。fixture在参数列表中可以明了地知道哪些tests使用了一个资源,无需人为地创建类,只需分离fixture应用。而对于一个资源而言,teardown代码是紧密地和setup代码耦合的。常常需在资源setup代码的位置处指定资源的生命周期的范围来节省测试时间。

一般而言,测试类以Test开头的类,但不能带有 _init_方法;测试文件以test开头或者结尾的文件;测试函数以test开头。pytest会自动进行收集测试用例,在pytest.ini配置文件中,python_classes指定测试类和测试文件、python_functions 指定测试函数。在setup.cfg文件中norecursedirs 指定禁止目录。

4.5 unittest2测试框架

unittest2测试框架是unittest的升级版,改善了API以及诊断语法。由于篇幅所限,只说明一点:可使用import unittest2 as unittest在unittest与unittest2之间进行切换。

5结束语

构建“TDD友好”的系统,需要进行分层架构,建立标准一致的系统,操作环境可控,努力创建高内聚低耦合的结构,在TDD实践过程可实现代码的低层设计。而TDD 并不能直接提高设计能力,它要求开发人员思想上重视测试,掌握重构与设计模式等知识,从而间接改善软件设计。

参考文献

[1] Beck,K.测试驱动开发(中文版) [M].孙平平译.北京:中国电力出版社, 2004.

[2] 雨痕.Python3学习笔记(上卷)[M].北京:电子工业出版社,2018.

[3] Matthew,K.Python机器学习实践,测试驱动的开发方法[M].刘江一,上官明乔,白皓,刘旭威译.北京:机械工业出版社,2017.