2010-02-28 42 views
12

编写Python测试的最新方法是什么?使用哪些模块/框架?如何编写现代Python测试?

还有另一个问题:是doctest测试还有什么价值?还是应该将所有测试写入更现代的测试框架?

谢谢,Boda Cydo。

回答

12

通常的方法是使用内置的unittest模块来创建单元测试并将它们捆绑在一起以便可以独立运行的测试套件。 unittest与jUnit非常相似(也受其启发),因此非常易于使用。

如果你有兴趣的最新变化,看看迈克尔Foord新PYCON谈话:

PyCon 2010: New and Improved: Coming changes to unittest

+0

感谢您的回答! – bodacydo 2010-02-28 20:47:01

5

我不知道很多关于文档测试,但在我的大学,鼻子测试是教和鼓励。

鼻可以按照这个程序(我假设你使用的是PC - Windows操作系统)安装:

  1. 安装setuptools
  2. 运行DOS命令提示符(开始 - >所有程序 - >附件 - >命令提示符)
  3. 对于此步骤工作,您必须连接到互联网。在DOS下输入:C:\ Python25 \脚本\ easy_install的鼻子

如果你是在一个不同的操作系统,检查this site

编辑

它已经两年,因为我原来写这个帖子。现在,我已经了解到这种编程原理Designing by Contract。这允许程序员为其代码中的所有函数定义先决条件,后置条件和不变量(称为契约)。结果是,如果违反了这些合同中的任何一个,就会产生错误。

在DBC的框架,我会建议蟒蛇被称为PyContract我已经成功地使用它在我的evolutionary programming framework

+0

我会看看这个。谢谢! – bodacydo 2010-02-28 20:41:06

+1

鼻子的有趣特征:不需要继承TestCase,为TestCase类灵活命名约定,也可以运行doctests。 – 2010-02-28 20:54:31

9

使用内置unittest模块的关联性和方便如初。其他单元测试选项py.test,nosetwisted.trial大多与unittest兼容。

Doctests具有相同的价值 - 它们非常适合测试您的文档,而不是您的代码。如果你打算在你的docstrings中放置代码示例,doctest可以保证你保持正确和最新。没有什么比试图复制一个例子和失败更糟,只是后来才意识到它实际上是文档的错。

+2

感谢您解释doctests。我不知道他们真正的目的,现在我知道了。我将尝试使用unittest进行测试。 :) – bodacydo 2010-02-28 20:56:48

+0

单元测试+1,我发现mox对帮助测试更复杂的代码很有用(http://code.google.com/p/pymox) – 2010-02-28 21:21:54

2

在我目前的项目中,我使用的是unittest,minimock,nose。在过去,我大量使用doctests,但在大型项目中,一些测试可能会变得笨重,所以我倾向于保留更简单函数的doctests的使用。

如果您正在使用setuptoolsdistribute(你应该切换到分发),你可以设置鼻子为默认的测试收集器,使您可以运行“蟒蛇setup.py测试”

setup(name='foo', 
     ... 
     test_suite='nose.collector', 
     ... 
你的测试

现在运行“python setup.py test”将会调用nose,它会抓取你的项目,看起来像测试并运行它们,并累计结果。如果您的项目中还有doctests,则可以使用--with-doctest选项运行nosetests以启用doctest插件。

鼻子也有coverage

nosetests --with-coverage. 

集成您还可以使用--cover-HTML --cover-HTML-DIR选项生成每个模块的HTML覆盖报告,每行未经测试的代码突出显示。我不会太过迷恋于报道覆盖所有模块的100%测试覆盖率。一些代码更适合集成测试,最后我会介绍这些代码。

我已经成为minimock的狂热粉丝,因为它使测试代码具有很多外部依赖关系非常简单。虽然它工作真的很好,当与doctest配对时,它可以使用任何测试框架使用unittest.TraceTracker类。我鼓励你尽量避免用它来测试你的代码的所有,因为你仍然应该尝试编写你的代码,以便每个翻译单元都可以独立测试而不会嘲笑。有时候这是不可能的。

这里有这样一个测试的使用minimock和单元测试的(未经测试)例如:

# tests/test_foo.py 
import minimock 
import unittest 

import foo 

class FooTest(unittest2.TestCase): 
    def setUp(self): 
     # Track all calls into our mock objects. If we don't use a TraceTracker 
     # then all output will go to stdout, but we want to capture it. 
     self.tracker = minimock.TraceTracker() 

    def tearDown(self): 
     # Restore all objects in global module state that minimock had 
     # replaced. 
     minimock.restore() 

    def test_bar(self): 
     # foo.bar invokes urllib2.urlopen, and then calls read() on the 
     # resultin file object, so we'll use minimock to create a mocked 
     # urllib2. 
     urlopen_result = minimock.Mock('urlobject', tracker=self.tracker) 
     urlopen_result.read = minimock.Mock(
      'urlobj.read', tracker=self.tracker, returns='OMG') 
     foo.urllib2.urlopen = minimock.Mock(
      'urllib2.urlopen', tracker=self.tracker, returns=urlopen_result) 

     # Now when we call foo.bar(URL) and it invokes 
     # *urllib2.urlopen(URL).read()*, it will not actually send a request 
     # to URL, but will instead give us back the dummy response body 'OMG', 
     # which it then returns. 
     self.assertEquals(foo.bar('http://example.com/foo'), 'OMG') 

     # Now we can get trace info from minimock to verify that our mocked 
     # urllib2 was used as intended. self.tracker has traced our calls to 
     # *urllib2.urlopen()* 
     minimock.assert_same_trace(self.tracker, """\ 
Called urllib2.urlopen('http://example.com/foo) 
Called urlobj.read() 
Called urlobj.close()""") 

单元测试不应该是唯一的种种考验你写的虽然。如果您计划在任何延长的时间段内维护此代码,它们当然非常有用,IMO也非常重要。它们使重构变得更容易,并帮助捕捉回归,但它们并不真正测试各个组件之间的交互以及它们如何相互作用(如果你做对了)。

当我开始得到的地方,我有一个主要的成品体面的测试覆盖率,我打算放开点,我喜欢写运行在一个孤立的环境中完整的程序,至少一个集成测试。

我在当前的项目中已经取得了很多成功。我有大约80%的单元测试覆盖率,其余的代码就像参数解析,命令调度和顶级应用程序状态,这在单元测试中很难涵盖。这个程序有很多外部依赖关系,碰到大约十几种不同的Web服务,并且与大约6000台机器进行交互,所以单独运行这个程序确实很困难。

我最终编写了一个集成测试,其中生成了一个用eventletwebob编写的WSGI服务器,它模拟我的程序在生产中与之交互的所有服务。然后,集成测试猴子修补我们web service client library拦截所有的HTTP请求,并将它们发送到WSGI应用。完成之后,它会加载一个状态文件,其中包含群集状态的序列化快照,并通过调用它的main()函数来调用该应用程序。现在,所有与我的程序交互的外部服务都是模拟的,这样我就可以运行我的程序,因为它将以可重复的方式在生产环境中运行。

0

要记住关于doctests的重要事情是,测试是基于字符串比较的,数字呈现为字符串的方式会因不同的平台甚至不同的python解释器而有所不同。

我的大部分工作都涉及计算,所以我只使用doctests来测试我的例子和我的版本字符串。我在__init__.py中放了一些,因为它会显示为我的epydoc生成的API文档的首页。

我使用鼻子进行测试,尽管我对检查py.test的最新变化非常感兴趣。