python之測試

16.1先測試 後編碼


16.1.1 精確的需求說明


16.1.2 爲改變而計劃

覆蓋度是測試知識中重要的部分。,優秀的測試程序組的目標之一是擁有良好的覆蓋度,實現這個目標的方法之一是使用覆蓋度工具


16.2測試工具

其中有兩個很棒的模塊可以協助你自動完成測試過程:

1.unitest:通用測試框架

2.doctest:簡單一些的模塊,是檢查文檔用的,但是對於編寫單元測試也很在行。



16.2.1 doctest

例如 假設求數字平方的函數,並且在文檔字符串中添加了一個例子

def square(x):

Squares a number and returns the result.

>>>square(2)

4

>>>square(3)

9

...

return x*x


文檔字符串中也包括了一些文本。這和測試又有什麼關係?假設square函數定義在my_math模塊中。


if __name__=='__main__':

import doctest,my_math

doctest.testmod(my_math)

可以只導入doctest和my_math模塊本身,然後運行doctest中的testmod函數。

$python my_math_.py



16.2.2 unitest

使用unittest框架的簡單測試

import unittest,my_math

class ProductTestCase(unittest.TestCase):

def testIntegers(self):

for x in xrange(-10,10):

for y in xrange(-10,10):

  p = my_math.product(x,y)

  self.failUnless(p == x*y,'Integer multiplication failed')

def testFloats(self):

for x in xrange(-10,10):

for y in xrange(-10,10):

x = x/10.0

y = y/10.0

p = my_math.product(x,y)

self.failUnless(p == x*y,'Float multiplication failed')

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


unittest.main函數負責運行測試。它會實例化所有TestCase子類,運行所有名字以test開頭的方法。

如果定義了叫做setUP和tearDown的方法,它們就會在運行每個測試方法之前和之後執行,這樣就可以用這些方法爲所有測試提供一般的初始化和清理代碼,這被稱爲測試夾具。

unittest模塊會區分由異常引發的錯誤和調用failUnless等函數而導致的失敗。下一步就是編寫概要代碼,這樣一來就沒錯誤---只有失敗。這就意味着要創建一個包含下列內容的模塊my_math。

def product(x,y):

pass

下一步讓測試代碼工作

def product(x,y):

return x * y

接下來修改product函數,讓它針對特定的數值7和9失敗。

def product(x,y):

if x==7 and y==9:

return 'An insidious bug has surfaced!'

else:

return x * y


16.3.1 使用PyChecker和PyLint檢查源代碼

pychecker file.py


pylint module


PyChecker和PyLint都可以作爲模塊導入,但是兩者並不是真正爲程序設計的。當導入pychecker.checker時,它會檢查之後的代碼,並且在標準輸出中打印警告。pylint.lint模塊有個叫做Run的非文檔記錄型函數,可以在pylint腳本本身中使用。


使用subprocess模塊調用外部檢查模塊

import unittest,my_math

from subprocess import Popen,PIPE

class ProductTestCase(unittest.TestCase):

def testWithPyCheck(self):

cmd = 'pychecker','-Q',my_math.__file__.rstrip('c')

pychecker = Popen(cmd,stdout=PIPE,stderr=PIPE)

self.assertEqual(pychecker.stdout.read(),'')

def testWithPyLint(self):

cmd = 'pylint','-rm','my_math'

pylint = Popen(cmd,stdout=PIPE,stderr=PIPE)

self.assertEqual(pylint.stdout.read(),'')

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

上面已經給出了檢查程序的幾個命令行開關,以避免無關的輸出干擾測試:對於pychecker來說,提供了-Q選項,而對於pylint,我提供了-rn(n意爲no)關閉報告,也就是說只顯示警告和錯誤。這裏使用了assertEqual函數以便使從stdout特性讀取的真正輸出顯示在unittest的失敗信息中。

pylint命令會直接同給定名稱的模塊一起運行,所以簡單多了。爲了能讓pycheck工作正常,我們還能獲取一個文件名。使用my_math模塊的__file__屬性獲取這個值,用rstrip剔除任何文件名末尾中可能出現的字符c。

爲了能讓PyLint不出現錯誤,我忽略重寫了my_math模塊。

"""

A simple math module

"""

__revision__ = '0.1'

def product(factor1,factor2):

'The product of two numbers'

return factor1 * factor2


16.3.2 分析

標準庫中已經包含了一個叫做profile的分析模塊。使用分析程序非常簡單,是要使用字符串參數調用它的run方法就行了

>>>import profile

>>>from my_math import product

>>>profile.run('product(1,2)')

如果提供了文件名,比如'my_math.profile'作爲第二個參數來運行,那麼結果就會保存到文件中。可以在之後使用pstats模塊檢查分析結果:

>>>import pstats

>>>p = pstats.Stats('my_math.profile')


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章