[Python unittest] 3-Organizing test code
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Python unittest] 3-Organizing test code相关的知识,希望对你有一定的参考价值。
-
组织测试代码
前面已经了解到测试的原理和步骤,但只是默认类string的测试,如果是我们自己写的类改怎么测试呢?
如下
class Widget(object): def __init__(self,name,width=50,height=50): self.name = name self.width = width self.height = height def __repr__(self): return "Widget({0})".format(self.name) # 返回大小 def size(self): return (self.width, self.height) #重设大小 def resize(self, *args): try: self.width = args[0] self.height = args[1] except: pass return self.size() #其他方法 def dispose(self): print ‘这里是tearDown‘ pass
测试用例可以这样写
import unittest class DefaultWidgetSizeTestCase(unittest.TestCase): def runTest(self): widget = Widget(‘The widget‘) self.assertEqual(widget.size(), (50, 50), ‘incorrect default size‘)
结果
python -m unittest users.tests.DefaultWidgetSizeTestCase . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
实际情况中,如果对该类我们有一百个测试用例需要写,难道要写100次widget = Widget(‘The widget‘)吗?我们猿类的服务宗旨是什么?从不写重复的代码
所以unittest给我们提供了setup,setup是每一个测试用例runTest之前都会执行的函数,相当于给我们提供了一个准备环境的方法import unittest class SimpleWidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget(‘The widget‘)
class DefaultWidgetSizeTestCase(SimpleWidgetTestCase): def runTest(self): self.assertEqual(self.widget.size(), (50,50), ‘incorrect default size‘) class WidgetResizeTestCase(SimpleWidgetTestCase): def runTest(self): self.widget.resize(100,150) self.assertEqual(self.widget.size(), (100,150), ‘wrong size after resize‘)python -m unittest users.tests .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
两个有 runTest 的测试用例都自动执行了父类的setup函数,当setup出错后,测试用例就不会执行了
相似的,unittest提供了在测试用例执行之后可以自动执行的方法tearDown,可以让我们做一些自己需要的事
class SimpleWidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget(‘The widget‘) def tearDown(self): self.widget.dispose() self.widget = None
python -m unittest users.tests 这里是tearDown .这里是tearDown . ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
只要setup成功,不论测试用例是否正确,tearDown都会执行
现在每一个测试用例都要继承相同的测试夹具,这让人感觉很不舒服,unittest提供了如下办法,很像java的JUnitclass WidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget(‘The widget‘) def tearDown(self): self.widget.dispose() self.widget = None def test_default_size(self): self.assertEqual(self.widget.size(), (50,50), ‘incorrect default size‘) def test_resize(self): self.widget.resize(100,150) self.assertEqual(self.widget.size(), (100,150), ‘wrong size after resize‘)
python -m unittest users.tests.WidgetTestCase 这里是tearDown .这里是tearDown . ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
这里没有runTest函数,而是用test_开头的方法代替,每一个test_开头的方法都会被当作一个测试独立运行,包括setup和tearDown也是独立的
如果只想运行部分测试用例改怎么办呢?if __name__ == ‘__main__‘: widgetTestSuite = unittest.TestSuite() widgetTestSuite.addTest(WidgetTestCase(‘test_default_size‘)) widgetTestSuite.addTest(WidgetTestCase(‘test_resize‘)) #suite = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase) unittest.TextTestRunner(verbosity=2).run(widgetTestSuite)
将你想运行的测试用例加入TestSuite
python */users/tests.py test_default_size (__main__.WidgetTestCase) ... 这里是tearDown ok test_resize (__main__.WidgetTestCase) ... 这里是tearDown ok ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK
或者将你想测试的类加载为suite,可以测试整个类的所有用例
if __name__ == ‘__main__‘: #widgetTestSuite = unittest.TestSuite() #widgetTestSuite.addTest(WidgetTestCase(‘test_default_size‘)) #widgetTestSuite.addTest(WidgetTestCase(‘test_resize‘)) suite = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase) unittest.TextTestRunner(verbosity=2).run(suite)
python */users/tests.py test_default_size (__main__.WidgetTestCase) ... 这里是tearDown ok test_resize (__main__.WidgetTestCase) ... 这里是tearDown ok ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK
更美观的做法是
if __name__ == ‘__main__‘: def suite(): suite = unittest.TestSuite() suite.addTest(WidgetTestCase(‘test_default_size‘)) suite.addTest(WidgetTestCase(‘test_resize‘)) return suite def suite_map(): tests = [‘test_default_size‘, ‘test_resize‘] return unittest.TestSuite(map(WidgetTestCase, tests)) unittest.TextTestRunner(verbosity=2).run(suite())
python */users/tests.py test_default_size (__main__.WidgetTestCase) ... 这里是tearDown ok test_resize (__main__.WidgetTestCase) ... 这里是tearDown ok ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
有时候需要阻止各个测试用例,很简单测试套件TestSuite像TestCase一样被加入TestSuite
if __name__ == ‘__main__‘: def suite(): suite = unittest.TestSuite() suite.addTest(WidgetTestCase(‘test_default_size‘)) suite.addTest(WidgetTestCase(‘test_resize‘)) return suite def suite_map(): tests = [‘test_default_size‘, ‘test_resize‘] return unittest.TestSuite(map(WidgetTestCase, tests)) alltest = unittest.TestSuite([suite(), suite_map()]) unittest.TextTestRunner(verbosity=2).run(alltest)
python */users/tests.py test_default_size (__main__.WidgetTestCase) ... 这里是tearDown ok test_resize (__main__.WidgetTestCase) ... 这里是tearDown ok test_default_size (__main__.WidgetTestCase) ... 这里是tearDown ok test_resize (__main__.WidgetTestCase) ... 这里是tearDown ok ---------------------------------------------------------------------- Ran 4 tests in 0.001s OK
测试代码可以放在任何地方,不过有几个原则需要注意:
- 测试模块可以独立在命令行执行
- 测试代码可以很容易的从项目中分离出来
- 没有合理的理由不要改变测试代码来适应它所测试的代码
- 代码的修改应该比测试代码的修改频繁的多
- 被测试代码重构更容易
- 用C编写的模块的测试无论如何必须是独立的模块,那么为什么不一致呢?
- 测试策略发生变化,不需要更改源代码
以上是关于[Python unittest] 3-Organizing test code的主要内容,如果未能解决你的问题,请参考以下文章