在Python中结合doctest和Epydoc产生敏捷文档的一种方法(ZT)

阅读更多
  摘要:Python是一种敏捷开发项目经常采用的语言。本文介绍了在Python敏捷项目中结合类似epydoc文档系统,使在doctest单元测试同时能够产生同步的最新文档,比如常用的功能说明文档等,在敏捷开发中常被称作敏捷文档。
  关键词:Python;敏捷开发;敏捷文档;doctest;单元测试;执行文档;epydoc
  中图分类号:TP311文献标识码:A文章编号:1009-3044(2007)04-11058-02
  
  1 引言
  在敏捷开发中单元测试是不可或缺的环节,单元测试除了保证了代码的质量外,在测试驱动开发中,测试更被改变地位,成为驱动开发主导的地位,每个功能的增加都必须写响应的单元测试以明确功能增加的目的性,形成的“测试-编码-重整”开发循环是敏捷开发的重要内容。
  众所周知,撰写文档是软件开发的重要部分。在测试驱动开发,程序员在单元测试中留下了大量的功能说明和功能使用代码,这些正是软件功能说明文档的素材,在python中利用doctest框架写出的单元测试更符合说明文档的需要,所以结合doctest和文档系统(epydoc)我们否找到一种方法:利用单位测试的注释和代码直接形成规格化的
  功能说明文档。
  
  2 doctest
  2.1 doctest介绍
  在Python中doctest就是把程序中的docstring作为范例来运行的一个框架。
  docstring可以由普通部分和执行部分组成,普通部分等同于原来的文字说明,执行部分由'>>>'(python shell提示符)或'...'提示符区分。程序员可以通过手工编写可预测的执行部分,也可以通过拷贝复制python交互式shell中的输入和输出简单的形成执行部分,doctest搜寻存在与各个模块,类和函数中的docstring,把每个可执行部分当成一次范例运行,再把实际运行值和期望值的对照作为一次运行结果。
  2.2 doctest:单元测试的新框架
  doctest常常用来完成三方面任务:保持文档与代码的同步;实现回归测试;可执行文档。这样就给测试框架多的Python又增加了一个不错的选择,对比其他测试框架(如unittest;py.test等)doctest具备了如下一些特点:
  (1)无需安装,从python 2.1版本开始被纳入标准库;
  (2)没有调用接口,使用方便,只需复制粘贴python shell中交互输入输出;
  (3)通过命令行参数可灵活控制测试的执行;
  (4)能很好地保持文档和代码的同步;
  (5)测试用例也独立存在与代码分离的文件中,它们可以包含特殊的边界测试用例等;
  (6)利用增强选项可增强输出文本匹配能力,比如ellipses选项,使地址,浮点数等可变输出得到正确匹配;
  (7)利用_test_变量,灵活选择测试用的docstring。
  利用doctest实现单元测试时,程序员独立创建只包含docstring的无函数体的测试函数实现测试单元,然后在docstring中编写测试说明和测试代码,它们是包含被测试目标的一些运行范例和期望的结果,利用doctest运行这些测试单元。
  我们约定在一个被测试模块中包含的所有测试单元列表称为:testlist;而模块中被测试目标所有测试单元的列表称为testmap。
  
  3 方法:结合单元测试doctest和epydoc开发敏捷文档
  epydoc是Python中一个功能强大的文档系统,结合类似epydoc这样的文档系统,使基于doctest的单元测试能够产生和代码同步的最新文档,这种文档不仅展示了代码中包含的所多个模块、类、方法、函数、变量,更重要的是,它还能提供许多程序功能的“动态的”使用范例。
  3.1 方法步骤
  我们下面将模拟doctest的单元测试过程,在docstring加入epydoc链接,最后用epydoc输出文档。
  (1)我们准备了要进行单元测试的模块P,包含一个类C;
  (2)我们开始给模块P中的C.M1方法写单元测试。
  方法是:在Python的交互窗口中运行C.M1的测试代码,然后复制&粘贴刚才的输入和输出到一个新的Python模块文件中(testlist_P),命名单元测试函数为test_M1,例子如下:
  def test_M1():
  """
  对M1测试行为的简短描述
  被测试目标:
  - L{P.C.M1}
  testlist_P模块的main部分如下:
  if _name_ == "_main_":
  import doctest
  doctest.testmod()
  这是doctest在单元测试中典型的运行方式。实际运行测试时,我们只需在命令行方式下输入“python testfile_P.py”。
  (3)现在,我们给方法C.M1补充初步的实现代码。在M1的docstring中,我们还增加一个Test Map的链接:
  def M1(self):
  """
  M1的描述
  Test map:
  - L{testmap_P.testmap_C_M1}
  """
  (4)利用程序自动生成我们需要的模块P的Test Map,命名为testmap_P.py,其中C.M1的Test map内容(即所有测试到C.M1的测试单元列表)如下:
  def testmap_C_M1():
  """
  Testmap for L{P.C.M1}:
  - L{testlist_P.test_M1}
  """
  (5)调用epydoc输出文档:
  epydoc -o P_docs P.py testlist_P.py testmap_P.py
  输出的文档在P_docs目录下,由于都是HTML格式文件,我们只需把它们移到web服务器文档目录下来就能发布出在线文档。
  当我们点击testlist_P模块链接,我们会看到模块P的testlist:
  Module P_docs.testlist_P
    当我们点击方法C.M1的docstring中的testmap链接,我们可以看到C.M1的testmap:
  Testmap for P.C.M1:
  * testlist_P.test_M1
  为C.M2重复步骤2-5
  (6)假设我们在单元测试方法M2时,同时也对M1测试,那么M2的测试函数test_M2可能是:
  def test_M2():
  """
  对M2测试行为的简短描述
  被测试目标
  - L{P.C.M1}
  - L{P.C.M2}
  >>> from P import C
  >>> c = C()
  >>> rc = c.M1()
  >>> print rc
  True
  >>> rc = c.M2()
  >>> print rc
  True
  """
  在“被测试目标”中,我们把两个函数都列出来了
  (7)在方法M2的docstring中添加testmap链接:
  def M2(self):
  """
  M2的描述
  Test map:
  - L{testmap_P.testmap_C_M2}
  """
  (8)利用程序重新生成模块的testmap,结果保存在testmap_P中,现在,C.M1的testmap将包含两个函数:test_M1,test_M2,而C.M2的testmap则包含test_M2:
  def testmap_C_M1():
  """
  Testmap for L{P.C.M1}:
  - L{testlist_P.test_M1}
  - L{testlist_P.test_M2}
  """
  def testmap_C_M2():
  """
  Testmap for L{P.C.M2}:
  - L{testlist_P.test_M2}
  """
  (9)运行epydoc输出文档:
  epydoc -o P_docs P.py testlist_P.py testmap_P.py
  我们点击testlist_P链接将看到:
  Module P_docs.testlist_P
  点击方法C.M1的docstring中的testmap链接:
  testmap_C_M1()
  Testmap for P.C.M1:
  * testlist_P.test_M1
  * testlist_P.test_M2
  (10)重复步骤2-5把每个单元测试添加到testlist_P模块中
  
  4 结束语
  我们可以发现doctest、epydoc的结合使得产生功能说明文档变得非常方便,同时也非常强大。这里敏捷文档或许还被称作"literate testing"被看的见的测试或"executable documentation"可执行的文档,但不管如何称呼,名字看来是不重要的,重要的是我们得到一种方法:我们通过单元测试docstring中的代码的方式,文档化模块的功能,没有比这更敏捷的方法了。
  参考文献:
  [1]Robert C·Martin. 敏捷软件开发——原则、模式与实践[M]. 清华大学出版社,2006.
  [2]Python Library Reference. http://docs.python.org/lib/module-doctest.html.
  [3]Epydoc Homepage. http://epydoc.sourceforge.net/.
  本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。

你可能感兴趣的:(Python,敏捷开发,单元测试,软件测试,C)