标签:
原文:https://www.ibm.com/developerworks/cn/linux/l-pyunit/
测试是一个贯穿于整个开发过程的连续过程,从某个意义上说,软件开发的过程实际上就是测试过程。正如Martin Fowler所说的"在你不知道如何测试代码之前,就不该编写程序。而一旦你完成了程序,测试代码也应该完成。除非测试成功,你不能认为你编写出了可以工作的程序。"
测试最基本的原理就是比较预期结果是否与实际执行结果相同,如果相同则测试成功,否则测试失败。为了更好地理解PyUnit这一自动测试框架的作用,先来看一个简单的例子,假设我们要对例1中的Widget类进行测试:
# 例1. widget.py # 将要被测试的类 class Widget: def __init__(self, size = (40, 40)): self._size = size def getSize(self): return self._size def resize(self, width, height): if width 0 or height < 0: raise ValueError, "illegal size" self._size = (width, height) def dispose(self): pass
采用手工方式进行单元测试的Python程序员很可能会写出类似例2的测试代码来,
# 例2. manual.py from widget import Widget # 执行测试的类 class TestWidget: def testSize(self): expectedSize = (40, 40); widget = Widget() if widget.getSize() == expectedSize: print "test [Widget]: getSize works perfected!" else: print "test [Widget]: getSize doesn‘t work!" # 测试 if __name__ == ‘__main__‘: myTest = TestWidget() myTest.testSize()
稍一留心你不难发现这种手工测试方法存在许多问题。首先,测试程序的写法没有一定的规范可以遵循,十个程序员完全可能写出十种不同的测试程序来,如果每个Python程序员都有自己不同的设计测试类的方法,光维护被测试的类就够麻烦了,谁还顾得上维护测试类。其次,需要编写大量的辅助代码才能进行单元测试,例1中用于测试的代码甚至比被测试的代码还要多,而这毫无疑问将增大Python程序员的工作量。
为了让单元测试代码能够被测试和维护人员更容易地理解,最好的解决办法是让开发人员遵循一定的规范来编写用于测试的代码,具体到Python程序员来讲,则是要采用PyUnit这一自动测试框架来构造单元测试用例。目前PyUnit已经得到了大多数Python开发人员的认可,成了事实上的单元测试标准。如果采用PyUnit来进行同样的测试,则测试代码将如例3所示:
# 例3. auto.py from widget import Widget import unittest # 执行测试的类 class WidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget() def tearDown(self): self.widget = None def testSize(self): self.assertEqual(self.widget.getSize(), (40, 40)) # 构造测试集 def suite(): suite = unittest.TestSuite() suite.addTest(WidgetTestCase("testSize")) return suite # 测试 if __name__ == "__main__": unittest.main(defaultTest = ‘suite‘)
在采用PyUnit这一单元测试框架后,用于测试的代码做了相应的改动:
虽然看起来有点复杂,但PyUnit使得所有的Python程序员都可以使用同样的单元测试方法,测试过程不再是杂乱无章的了,而是在同一规范指导下进行的有序行为,这就是使用PyUnit这一自动单元测试框架所带来的最大好处。
-----------------------------------------------------------------------------------
废话介绍完了
-----------------------------------------------------------------------------------
PyUnit模块中定义了一个名为main的全局方法,使用它可以很方便地将一个单元测试模块变成可以直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中的测试方法,并自动执行它们。如果Python程序员能够按照约定(以test开头)来命名所有的测试方法,那就只需要在测试模块的最后加入如下几行代码即可:
if __name__ == "__main__": unittest.main()
使用TestRunner来实施测试的例子如例7所示,
# 例7. text_runner.py from widget import Widget import 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)
PyUnit模块中定义了一个名为main的全局方法,使用它可以很方便地将一个单元测试模块变成可以直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中的测试方法,并自动执行它们。如果Python程序员能够按照约定(以test开头)来命名所有的测试方法,那就只需要在测试模块的最后加入如下几行代码即可:
if __name__ == "__main__": unittest.main()
测试类WidgetTestCase中的所有测试方法都将被自动执行,但如果只想执行testSize()方法,可以使用如下命令:
python main_runner.py WidgetTestCase.testSize
为了使单元测试更具亲合力,PyUnit软件包中还提供了一个图形界面测试脚本unittestgui.py,将其复制到当前目录后,可以执行下面的命令来启动该测试工具,对main_runner.py脚本中的所有测试用例进行测试:
python unittestgui.py main_runner
测试是保证软件质量的关键,新的软件开发方法要求程序员在编写代码前先编写测试用例,并在软件开发过程中不断地进行单元测试,从而最大限度地减少缺陷(Bug)的产生。软件单元测试是XP方法的基石,测试框架为程序员进行单元测试提供了统一的规范,Python程序员可以使用PyUnit作为软件开发过程中的自动单元测试框架。
标签:
原文地址:http://www.cnblogs.com/addf/p/4982645.html