Python 单元测试框架

Python 单元测试框架

时间:2015-07-08 09:22来源:网络整理 作者:KKWL 点击:
目录 概况 Python单元测试框架(The Python unit testing framework),简称为PyUnit, 是Kent Beck和Erich Gamma这两位聪明的家伙所设计的 JUnit 的Python版本。 而JUnit又是Kent设计的Smalltalk测试框架的Ja

目录 概况

Python单元测试框架(The Python unit testing framework),简称为PyUnit, 是Kent Beck和Erich Gamma这两位聪明的家伙所设计的 JUnit 的Python版本。 而JUnit又是Kent设计的Smalltalk测试框架的Java版本。它们都是各自语言的标准测试框架。

此文档仅阐述针对Python的单元测试PyUnit的设计与使用。如需单元测试框架基本设计的背景 信息,请查阅Kent的原始文章"Simple Smalltalk Testing: With Patterns"。

自从 Python 2.1 版本后,PyUnit成为 Python标准库的一部分。

以下内容默认您已经了解Python。我觉得Python 非常简单易学而且让人欲罢不能。

系统要求

PyUnit可以在Python 1.5.2及更高版本上运行。

作者已经在Linux(Redhat 6.0和6.1以及Debian Potato)和Python 1.5.2, 2.0和2.1上对PyUnit 进行了测试。而且PyUnit已知可以在其它操作系统平台上工作,如Windows和Mac。如果您在 任何系统平台或Python版本中遇到麻烦,请让我知道。

如需了解在JPython和Jython中使用PyUnit的细节,请阅读 部分。

使用PyUnit构建自己的测试 安装

编写测试所需的类可以在“unittest”模块中找到。此模块是Python 2.1和更高版本的标准 库的一部分。如果你在使用更早版本的Python,你应该从单独的PyUnit发布中获得此模块。

为使此模块能在你的代码中正常工作,你只需确保包含“unittest.py”文件的目录 在你的Python搜索路径中。为此,你可以修改环境变量“$PYTHONPATH”或将此文件 放入当前Python搜索路径中的某一个目录中,比如在Redhat Linux系统中的 /usr/lib/python1.5/site-packages目录。

注意,你只有完成此项工作才能运行PyUnit所自带的例子,除非你将“unittest.py”复制到 例子目录。

测试用例介绍

单元测试是由一些测试用例(Test Cases)构建组成的。测试用例是被设置用来检测正确性的 单独的场景。在PyUnit中,unittest模块中的TestCase 类代表测试用例。

TestCase类的实例是可以完全运行测试方法和可选的设置 (set-up)以及清除(tidy-up)代码的对象。

TestCase实例的测试代码必须是自包含的,换言之,它 可以单独运行或与其它任意数量的测试用例共同运行。

创建一个简单测试用例

通过覆盖runTest方法即可得到最简单的测试用例子类以运行 一些测试代码:

import unittest class DefaultWidgetSizeTestCase(unittest.TestCase): def runTest(self): widget = Widget("The widget") assert widget.size() == (50,50), 'incorrect default size'

注意:为进行测试,我们只是使用了Python内建的“assert”语句。如果在测试用例 运行时断言(assertion)为假,AssertionError异常会被抛出,并且 测试框架会认为测试用例失败。其它非“assert”检查所抛出的异常会被测试框架认为是“errors”。 (参见)

运行测试用例的方法会在后面介绍。现在我们只是通过调用无参数的构造器(constructor) 来创建一个测试用例的实例:

testCase = DefaultWidgetSizeTestCase() 复用设置代码:创建固件

现在,这样的测试用例数量巨大且它们的设置需要很多重复性工作。在上面的测试用例中, 如若在100个Widget测试用例的每一个子类中都创建一个“Widget”,那会导致难看的重复。

幸运的是,我们可以将这些设置代码提取出来并放置在一个叫做setUp的 钩子方法(hook method)中。测试框架会在运行测试时自动调用此方法:

import unittest class SimpleWidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget("The widget") class DefaultWidgetSizeTestCase(SimpleWidgetTestCase): def runTest(self): assert self.widget.size() == (50,50), 'incorrect default size' class WidgetResizeTestCase(SimpleWidgetTestCase): def runTest(self): self.widget.resize(100,150) assert self.widget.size() == (100,150), \ 'wrong size after resize'

如果setUp方法在测试运行时抛出异常,框架会认为测试遇到了错误并且runTest不会被执行。

类似的,我们也可以提供一个tearDown方法来完成在runTest运行之后的清理工作:

import unittest class SimpleWidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget("The widget") def tearDown(self): self.widget.dispose() self.widget = None

如果setUp执行成功, 那么无论runTest是否成功,tearDown方法都将被执行。

Such a working environment for the testing code is termed a fixture. 这个测试代码的运行环境被称为固件(fixture,译者注:此为暂定译法,意为固定的构件或方法)。

包含多个测试方法的测试用例类

很多小型测试用例经常会使用相同的固件。在这个用例中,我们最终从SimpleWidgetTestCase继承产生很多仅包含一个方法的类,如DefaultWidgetSizeTestCase。这是很耗时且不被鼓励的,因此,沿用JUnit的风格,PyUnit提供了一个更简便的方法:

import unittest class WidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget("The widget") def tearDown(self): self.widget.dispose() self.widget = None def testDefaultSize(self): assert self.widget.size() == (50,50), 'incorrect default size' def testResize(self): self.widget.resize(100,150) assert self.widget.size() == (100,150), \ 'wrong size after resize'
------分隔线----------------------------