Python之自动单元测试之一(unittest使用实例)

1 测试用例TestCase

软件测试中最基本的组成单元是测试用例(test case),PyUnit使用TestCase类来表示测试用例,并要求所有用于执行测试的类都必须从该类继承。TestCase子类实现的测试代码应该是自包含(self contained)的,也就是说测试用例既可以单独运行,也可以和其它测试用例构成集合共同运行。

TestCase在PyUnit测试框架中被视为测试单元的运行实体,Python程序员可以通过它派生自定义的测试过程与方法(测试单元),利用Command和Composite设计模式,多个TestCase还可以组合成测试用例集合。PyUnit测试框架在运行一个测试用例时,TestCase子类定义的setUp()、runTest()和tearDown()方法被依次执行,最简单的测试用例只需覆盖runTest()方法来执行特定的测试代码就可以了,如例4所示:

 static_single.pyimport unittest# 执行测试的类class WidgetTestCase(unittest.TestCase):    def runTest(self):        widget = Widget()        self.assertEqual(widget.getSize(), (40, 40))

而要在PyUnit测试框架中构造上述WidgetTestCase类的一个实例,应该不带任何参数调用其构造函数:

testCase = WidgetTestCase()

一个测试用例通常只对软件模块中的一个方法进行测试,采用覆盖runTest()方法来构造测试用例在PyUnit中称为静态方法,如果要对同一个软件模块中的多个方法进行测试,通常需要构造多个执行测试的类,如例5所示:

 static_multi.pyimport unittest# 测试getSize()方法的测试用例class WidgetSizeTestCase(unittest.TestCase):    def runTest(self):        widget = Widget()        self.assertEqual(widget.getSize(), (40, 40))# 测试resize()方法的测试用例class WidgetResizeTestCase(unittest.TestCase):    def runTest(self):        widget = Widget()        widget.resize(100, 100)        self.assertEqual(widget.getSize(), (100, 100))

采用静态方法,Python程序员不得不为每个要测试的方法编写一个测试类(该类通过覆盖runTest()方法来执行测试),并在每一个测试类中生成一个待测试的对象。在为同一个软件模块编写测试用例时,很多时候待测对象有着相同的初始状态,因此采用上述方法的Python程序员不得不在每个测试类中为待测对象进行同样的初始化工作,而这往往是一项费时且枯燥的工作。

一种更好的解决办法是采用PyUnit提供的动态方法,只编写一个测试类来完成对整个软件模块的测试,这样对象的初始化工作可以在setUp()方法中完成,而资源的释放则可以在tearDown()方法中完成,如例6所示:

 dynamic.pyimport unittest# 执行测试的类class WidgetTestCase(unittest.TestCase):    def setUp(self):        self.widget = Widget()    def tearDown(self):        self.widget.dispose()        self.widget = None    def testSize(self):        self.assertEqual(self.widget.getSize(), (40, 40))    def testResize(self):        self.widget.resize(100, 100)        self.assertEqual(self.widget.getSize(), (100, 100))

采用动态方法最大的好处是测试类的结构非常好,用于测试一个软件模块的所有代码都可以在同一个类中实现。动态方法不再覆盖runTest()方法,而是为测试类编写多个测试方法(按习惯这些方法通常以test开头),在创建TestCase子类的实例时必须给出测试方法的名称,来为PyUnit测试框架指明运行该测试用例时究竟应该调用测试类中的哪个方法:

sizeTestCase = WidgetTestCase("testSize")resizeTestCase = WidgetTestCase("testResize")
2 测试用例集TestSuite

完整的单元测试很少只执行一个测试用例,开发人员通常都需要编写多个测试用例才能对某一软件功能进行比较完整的测试,这些相关的测试用例称为一个测试用例集,在PyUnit中是用TestSuite类来表示的。

在创建了一些TestCase子类的实例作为测试用例之后,下一步要做的工作就是用TestSuit类来组织它们。PyUnit测试框架允许Python程序员在单元测试代码中定义一个名为suite()的全局函数,并将其作为整个单元测试的入口,PyUnit通过调用它来完成整个测试过程。

def suite():    suite = unittest.TestSuite()    suite.addTest(WidgetTestCase("testSize"))    suite.addTest(WidgetTestCase("testResize"))    return suite

也可以直接定义一个TestSuite的子类,并在其初始化方法(__init__)中完成所有测试用例的添加:

class WidgetTestSuite(unittest.TestSuite):    def __init__(self):        unittest.TestSuite.__init__(self, map(WidgetTestCase,                                              ("testSize",                                               "testResize")))

这样只需要在suite()方法中返回该类的一个实例就可以了:

def suite():    return WidgetTestSuite()

如果用于测试的类中所有的测试方法都以test开,Python程序员甚至可以用PyUnit模块提供的makeSuite()方法来构造一个TestSuite:

def suite():    return unittest.makeSuite(WidgetTestCase, "test")

在PyUnit测试框架中,TestSuite类可以看成是TestCase类的一个容器,用来对多个测试用例进行组织,这样多个测试用例可以自动在一次测试中全部完成。事实上,TestSuite除了可以包含TestCase外,也可以包含TestSuite,从而可以构成一个更加庞大的测试用例集:

suite1 = mysuite1.TheTestSuite()suite2 = mysuite2.TheTestSuite()alltests = unittest.TestSuite((suite1, suite2))
3 实施测试

编写测试用例(TestCase)并将它们组织成测试用例集(TestSuite)的最终目的只有一个:实施测试并获得最终结果。PyUnit使用TestRunner类作为测试用例的基本执行环境,来驱动整个单元测试过程。Python开发人员在进行单元测试时一般不直接使用TestRunner类,而是使用其子类TextTestRunner来完成测试,并将测试结果以文本方式显示出来:

runner = unittest.TextTestRunner()runner.run(suite)

使用TestRunner来实施测试的例子如例7所示,

 text_runner.pyfrom widget import Widgetimport unittest# 执行测试的类class WidgetTestCase(unittest.TestCase):    def setUp(self):        self.widget = Widget()    def tearDown(self):        self.widget.dispose()        self.widget = None    def testSize(self):        self.assertEqual(self.widget.getSize(), (40, 40))    def testResize(self):        self.widget.resize(100, 100)                self.assertEqual(self.widget.getSize(), (100, 100))        # 测试if __name__ == "__main__":    # 构造测试集    suite = unittest.TestSuite()    suite.addTest(WidgetTestCase("testSize"))    suite.addTest(WidgetTestCase("testResize"))        # 执行测试    runner = unittest.TextTestRunner()    runner.run(suite)

运行结果应该如下所示,表明执行了2个测试用例,并且两者都通过了测试:

..----------------------------------------------------------------------Ran 2 tests in 0.000sOK

如果对数据进行修改,模拟出错的情形,将会得到如下结果:

.F==========================================FAIL: testResize (__main__.WidgetTestCase)----------------------------------------------------------------------Traceback (most recent call last):  File "text_runner.py", line 15, in testResize    self.assertEqual(self.widget.getSize(), (200, 100))  File "/usr/lib/python2.2/unittest.py", line 286, in failUnlessEqual    raise self.failureException, /AssertionError: (100, 100) != (200, 100)----------------------------------------------------------------------Ran 2 tests in 0.001sFAILED (failures=1)

默认情况下,TextTestRunner将结果输出到sys.stderr上,但如果在创建TextTestRunner类实例时将一个文件对象传递给了构造函数,则输出结果将被重定向到该文件中。在Python的交互环境中驱动单元测试时,使用TextTestRunner类是一个不错的选择。

PyUnit模块中定义了一个名为main的全局方法,使用它可以很方便地将一个单元测试模块变成可以直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中的测试方法,并自动执行它们。如果Python程序员能够按照约定(以test开头)来命名所有的测试方法,那就只需要在测试模块的最后加入如下几行代码即可:

if __name__ == "__main__":    unittest.main()

使用main()方法来实施测试的例子如例8所示:

 main_runner.pyfrom widget import Widgetimport unittest# 执行测试的类class WidgetTestCase(unittest.TestCase):    def setUp(self):        self.widget = Widget()    def tearDown(self):        self.widget.dispose()        self.widget = None    def testSize(self):        self.assertEqual(self.widget.getSize(), (40, 40))    def testResize(self):        self.widget.resize(100, 100)        self.assertEqual(self.widget.getSize(), (100, 100))   # 测试if __name__ == "__main__":    unittest.main()

为了使单元测试更具亲合力,PyUnit软件包中还提供了一个图形界面测试脚本unittestgui.py,将其复制到当前目录后,可以执行下面的命令来启动该测试工具,对main_runner.py脚本中的所有测试用例进行测试:

python unittestgui.py main_runner

四、小结

测试是保证软件质量的关键,新的软件开发方法要求程序员在编写代码前先编写测试用例,并在软件开发过程中不断地进行单元测试,从而最大限度地减少缺陷(Bug)的产生。软件单元测试是XP方法的基石,测试框架为程序员进行单元测试提供了统一的规范,Python程序员可以使用PyUnit作为软件开发过程中的自动单元测试框架。

时间: 2024-10-18 09:07:57

Python之自动单元测试之一(unittest使用实例)的相关文章

python 学习6 单元测试框架-unittest

参考资料:https://docs.python.org/3.4/library/unittest.html#module-unittest 一张图解决问题: 涉及5块内容:case.suite.loader.runner.result 1 case: TestCase(测试用例) :所有测试用例的基本类,给一个测试方法的名字,返回一个测试用例实例. 2 suite: TestSuite(测试套):组织测试用例的实例,支持测试用例的添加和删除,最终将传递给testRunner进行测试执行 3 l

python中的单元测试模块unittest

unittest的属性: 该文以思维导图的形式描述unittest的重要属性. 其中前四个是unittest最核心的三个属性. testcase:测试用例: testsuite:测试套件,多个测试用例组成一个测试套件: test runner:执行测试用例,该类中的run()方法会执行testsuite/testcase中的run()方法.测试的结果会保存在testresult中. 还有一个很重要的就是fixture,看着是挺陌生的,其实就是一个测试用例执行之前环境的准备和执行之后环境的销毁.

[转] Python自动单元测试框架

一.软件测试 大型软件系统的开发是一个很复杂的过程,其中因为人的因素而所产生的错误非常多,因此软件在开发过程必须要有相应的质量保证活动,而软件测试则是保证质量的关键措施.正像软件熵(software entropy)所描述的那样:一个程序从设计很好的状态开始,随着新的功能不断地加入,程序逐渐地失去了原有的结构,最终变成了一团乱麻(其实最初的"很好的状态"得加个问号).测试的目的说起来其实很简单也极具吸引力,那就是写出高质量的软件并解决软件熵这一问题. 可惜的是,软件开发人员很少能在编码

Python自动单元测试框架

原文链接:http://www.ibm.com/developerworks/cn/linux/l-pyunit/ 软件的测试是一件非常乏味的事情,在测试别人编写的软件时尤其如此,程序员通常都只对编写代码感兴趣,而不喜欢文档编写和软件测试这类"没有创新"的工作.既然如此,为什么不让程序员在编写软件时自己加入一些用于测试的代码,使测试过程自动化呢?在软件工程中,这一技术称为自动单元测试,本文介绍在用Python开发软件时如何实现这一目标. 一.软件测试 大型软件系统的开发是一个很复杂的过

Python自动单元测试框架(摘要笔记)

规范Python单元测试 原文:https://www.ibm.com/developerworks/cn/linux/l-pyunit/ 测试是一个贯穿于整个开发过程的连续过程,从某个意义上说,软件开发的过程实际上就是测试过程.正如Martin Fowler所说的"在你不知道如何测试代码之前,就不该编写程序.而一旦你完成了程序,测试代码也应该完成.除非测试成功,你不能认为你编写出了可以工作的程序." 测试最基本的原理就是比较预期结果是否与实际执行结果相同,如果相同则测试成功,否则测试

Python单元测试框架unittest之深入学习

前言 前几篇文章该要地介绍了python单元测试框架unittest的使用,本篇文章系统介绍unittest框架. 一.unittest核心工作原理 unittest中最核心的四个概念是:test case, test suite, test runner, test fixture. 下面我们分别来解释这四个概念的意思,先来看一张unittest的静态类图(下面的类图以及解释均来源于网络,原文链接): 一个TestCase的实例就是一个测试用例.什么是测试用例呢?就是一个完整的测试流程,包括测

Python单元测试:unittest使用简介

一.概述 本文介绍python的单元测试框架unittest,这是Python自带的标准模块unittest.unittest是基于java中的流行单元测试框架junit设计的,其功能强大且灵活,对于熟悉junit的人来说掌握unittest很简单. unittest涉及的知识点较多,但核心的就那一些,本文只介绍最核心和基础的内容. 类似junit,使用unittest编写python的单元测试代码,包括如下几个步骤: 1)编写一个python类,继承 unittest模块中的TestCase类

Python单元测试框架unittest测试过程简介

测试步骤 1. 导入unittest模块 import unittest 2. 编写测试的类继承unittest.TestCase class Tester(unittest.TestCase) 3. 编写测试的方法必须以test开头 def test_add(self) def test_sub(self) 4.使用TestCase class提供的方法测试功能点 Method Checks that New in assertEqual(a, b) a == b   assertNotEqu

单元测试框架Unittest

Unittest官方 4个重要概念: Test fixture(测试固件):初始化.清除 Test case(测试用例),test suite(测试套件),test runner(测试运行器) 两种单元测试加载方法: 1.unittest.main() 2.将所有test case 添加到test suit中,然后一次性加载 知识点: 1.测试类要继承unittest.TestCase类 2.每个用例方法 test开头(self) 3.setUp和tearDown方法在每个用例执行前后都会执行