[Python unittest] 3-Organizing test code
?
-
組織測試代碼
前面已經了解到測試的原理和步驟,但只是默認類string的測試,如果是我們自己寫的類改怎么測試呢?
如下
class Widget(object):def __init__(self,name,width=50,height=50):self.name = nameself.width = widthself.height = heightdef __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:passreturn self.size()#其他方法def dispose(self):print '這里是tearDown'pass?測試用例可以這樣寫
import unittestclass 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.000sOK?實際情況中,如果對該類我們有一百個測試用例需要寫,難道要寫100次widget = Widget('The widget')嗎?我們猿類的服務宗旨是什么?從不寫重復的代碼
import unittestclass SimpleWidgetTestCase(unittest.TestCase):def setUp(self):self.widget = Widget('The widget')
所以unittest給我們提供了setup,setup是每一個測試用例runTest之前都會執行的函數,相當于給我們提供了一個準備環境的方法
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.000sOK?兩個有 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.000sOK?只要setup成功,不論測試用例是否正確,tearDown都會執行
class WidgetTestCase(unittest.TestCase):def setUp(self):self.widget = Widget('The widget')def tearDown(self):self.widget.dispose()self.widget = Nonedef 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')
現在每一個測試用例都要繼承相同的測試夾具,這讓人感覺很不舒服,unittest提供了如下辦法,很像java的JUnit?
python -m unittest users.tests.WidgetTestCase 這里是tearDown .這里是tearDown . ---------------------------------------------------------------------- Ran 2 tests in 0.000sOK?這里沒有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.001sOK?或者將你想測試的類加載為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.001sOK?更美觀的做法是
if __name__ == '__main__':def suite():suite = unittest.TestSuite()suite.addTest(WidgetTestCase('test_default_size'))suite.addTest(WidgetTestCase('test_resize'))return suitedef 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.000sOK?有時候需要阻止各個測試用例,很簡單測試套件TestSuite像TestCase一樣被加入TestSuite
if __name__ == '__main__':def suite():suite = unittest.TestSuite()suite.addTest(WidgetTestCase('test_default_size'))suite.addTest(WidgetTestCase('test_resize'))return suitedef 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.001sOK?
測試代碼可以放在任何地方,不過有幾個原則需要注意:
- 測試模塊可以獨立在命令行執行
- 測試代碼可以很容易的從項目中分離出來
- ?????? 沒有合理的理由不要改變測試代碼來適應它所測試的代碼
- ?????? 代碼的修改應該比測試代碼的修改頻繁的多
- ?????? 被測試代碼重構更容易
- ?????? 用C編寫的模塊的測試無論如何必須是獨立的模塊,那么為什么不一致呢?
- ?????? 測試策略發生變化,不需要更改源代碼
轉載于:https://www.cnblogs.com/lazySmeagol/p/7452460.html
總結
以上是生活随笔為你收集整理的[Python unittest] 3-Organizing test code的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么将string list 转成有特殊
- 下一篇: websocket python爬虫_p