一、軟件測試
大型軟件系統的開發是一個很復雜的過程,其中因為人的因素而所產生的錯誤非常多,因此軟件在開發過程必須要有相應的質量保證活動,而軟件測試則是保證質量的關鍵措施。正像軟件熵(software entropy)所描述的那樣:一個程序從設計很好的狀態開始,隨著新的功能不斷地加入,程序逐漸地失去了原有的結構,最終變成了一團亂麻(其實最初的"很好的狀態"得加個問號)。測試的目的說起來其實很簡單也極具吸引力,那就是寫出高質量的軟件并解決軟件熵這一問題。
可惜的是,軟件開發人員很少能在編碼的過程中就進行軟件測試,大部分軟件項目都只在最終驗收時才進行測試,有些項目甚至根本沒有測試計劃!隨著軟件質量意識的增強,許多軟件開發組織開始轉向UML、CMM、RUP、XP等軟件工程方法,以期提高軟件質量,并使軟件開發過程更加可控,好在這些方法對測試都提出了很嚴格的要求,從而使得測試在軟件開發過程的作用開始真正體現出來。
軟件測試作為一種系統工程,涉及到整個軟件開發過程的各個方面,需要管理人員、設計人員、開發人員和測試人員的共同努力。作為軟件開發過程中的主要力量,現今的程序員除了要編寫實現代碼外,還承擔著單元測試這一艱巨任務,因此必須采用新的工作模式:
編寫和維護一套詳盡的單元測試用例;先構造單元測試和驗收測試用例,然后再編寫代碼;根據構造的測試用例來編寫代碼。單元測試負責對最小的軟件設計單元(模塊)進行驗證,它使用軟件設計文檔中對模塊的描述作為指南,對重要的程序分支進行測試以發現模塊中的錯誤。由于軟件模塊并不是一個單獨的程序,為了進行單元測試還必須編寫大量額外的代碼,從而無形中增加了開發人員的工作量,目前解決這一問題比較好的方法是使用測試框架。測試框架是在用XP方法進行單元測試時的關鍵,尤其是在需要構造大量測試用例時更是如此,因為如果完全依靠手工的方式來構造和執行這些測試,肯定會變成一個花費大量時間并且單調無味的工作,而測試框架則可以很好地解決這些問題。
使用Python語言的開發人員可以使用Steve Purcell編寫的PyUnit作為單元測試框架,通過將單元測試融合到PyUnit這一測試框架里,Python程序員可以更容易地增加、管理、執行測試用例,并對測試結果進行分析。此外,使用PyUnit還可以實現自動單元測試(回歸測試)。
二、規范Python單元測試
測試是一個貫穿于整個開發過程的連續過程,從某個意義上說,軟件開發的過程實際上就是測試過程。正如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.pyfrom 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.pyfrom widget import Widgetimport 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這一單元測試框架后,用于測試的代碼做了相應的改動:
用import語句引入unittest模塊。讓所有執行測試的類都繼承于TestCase類,可以將TestCase看成是對特定類進行測試的方法的集合。在setUp()方法中進行測試前的初始化工作,并在tearDown()方法中執行測試后的清除工作,setUp()和tearDown()都是TestCase類中定義的方法。在testSize()中調用assertEqual()方法,對Widget類中getSize()方法的返回值和預期值進行比較,確保兩者是相等的,assertEqual()也是TestCase類中定義的方法。提供名為suite()的全局方法,PyUnit在執行測試的過程調用suit()方法來確定有多少個測試用例需要被執行,可以將TestSuite看成是包含所有測試用例的一個容器。雖然看起來有點復雜,但PyUnit使得所有的Python程序員都可以使用同樣的單元測試方法,測試過程不再是雜亂無章的了,而是在同一規范指導下進行的有序行為,這就是使用PyUnit這一自動單元測試框架所帶來的最大好處。
原文轉自:http://www.anti-gravitydesign.com