2010-02-28 60 views
12

編寫Python測試的最新方法是什麼?使用哪些模塊/框架?如何編寫現代Python測試?

還有另一個問題:是doctest測試還有什麼價值?還是應該將所有測試寫入更現代的測試框架?

謝謝,Boda Cydo。

回答

12

通常的方法是使用內置的unittest模塊來創建單元測試並將它們捆綁在一起以便可以獨立運行的測試套件。 unittest與jUnit非常相似(也受其啓發),因此非常易於使用。

如果你有興趣的最新變化,看看邁克爾Foord新PYCON談話:

PyCon 2010: New and Improved: Coming changes to unittest

+0

感謝您的回答! – bodacydo 2010-02-28 20:47:01

5

我不知道很多關於文檔測試,但在我的大學,鼻子測試是教和鼓勵。

鼻可以按照這個程序(我假設你使用的是PC - Windows操作系統)安裝:

  1. 安裝setuptools
  2. 運行DOS命令提示符(開始 - >所有程序 - >附件 - >命令提示符)
  3. 對於此步驟工作,您必須連接到互聯網。在DOS下輸入:C:\ Python25 \腳本\ easy_install的鼻子

如果你是在一個不同的操作系統,檢查this site

編輯

它已經兩年,因爲我原來寫這個帖子。現在,我已經瞭解到這種編程原理Designing by Contract。這允許程序員爲其代碼中的所有函數定義先決條件,後置條件和不變量(稱爲契約)。結果是,如果違反了這些合同中的任何一個,就會產生錯誤。

在DBC的框架,我會建議蟒蛇被稱爲PyContract我已經成功地使用它在我的evolutionary programming framework

+0

我會看看這個。謝謝! – bodacydo 2010-02-28 20:41:06

+1

鼻子的有趣特徵:不需要繼承TestCase,爲TestCase類靈活命名約定,也可以運行doctests。 – 2010-02-28 20:54:31

9

使用內置unittest模塊的關聯性和方便如初。其他單元測試選項py.test,nosetwisted.trial大多與unittest兼容。

Doctests具有相同的價值 - 它們非常適合測試您的文檔,而不是您的代碼。如果你打算在你的docstrings中放置代碼示例,doctest可以保證你保持正確和最新。沒有什麼比試圖複製一個例子和失敗更糟,只是後來才意識到它實際上是文檔的錯。

+2

感謝您解釋doctests。我不知道他們真正的目的,現在我知道了。我將嘗試使用unittest進行測試。 :) – bodacydo 2010-02-28 20:56:48

+0

單元測試+1,我發現mox對幫助測試更復雜的代碼很有用(http://code.google.com/p/pymox) – 2010-02-28 21:21:54

2

在我目前的項目中,我使用的是unittest,minimock,nose。在過去,我大量使用doctests,但在大型項目中,一些測試可能會變得笨重,所以我傾向於保留更簡單函數的doctests的使用。

如果您正在使用setuptoolsdistribute(你應該切換到分發),你可以設置鼻子爲默認的測試收集器,使您可以運行「蟒蛇setup.py測試」

setup(name='foo', 
     ... 
     test_suite='nose.collector', 
     ... 
你的測試

現在運行「python setup.py test」將會調用nose,它會抓取你的項目,看起來像測試並運行它們,並累計結果。如果您的項目中還有doctests,則可以使用--with-doctest選項運行nosetests以啓用doctest插件。

鼻子也有coverage

nosetests --with-coverage. 

集成您還可以使用--cover-HTML --cover-HTML-DIR選項生成每個模塊的HTML覆蓋報告,每行未經測試的代碼突出顯示。我不會太過迷戀於報道覆蓋所有模塊的100%測試覆蓋率。一些代碼更適合集成測試,最後我會介紹這些代碼。

我已經成爲minimock的狂熱粉絲,因爲它使測試代碼具有很多外部依賴關係非常簡單。雖然它工作真的很好,當與doctest配對時,它可以使用任何測試框架使用unittest.TraceTracker類。我鼓勵你儘量避免用它來測試你的代碼的所有,因爲你仍然應該嘗試編寫你的代碼,以便每個翻譯單元都可以獨立測試而不會嘲笑。有時候這是不可能的。

這裏有這樣一個測試的使用minimock和單元測試的(未經測試)例如:

# tests/test_foo.py 
import minimock 
import unittest 

import foo 

class FooTest(unittest2.TestCase): 
    def setUp(self): 
     # Track all calls into our mock objects. If we don't use a TraceTracker 
     # then all output will go to stdout, but we want to capture it. 
     self.tracker = minimock.TraceTracker() 

    def tearDown(self): 
     # Restore all objects in global module state that minimock had 
     # replaced. 
     minimock.restore() 

    def test_bar(self): 
     # foo.bar invokes urllib2.urlopen, and then calls read() on the 
     # resultin file object, so we'll use minimock to create a mocked 
     # urllib2. 
     urlopen_result = minimock.Mock('urlobject', tracker=self.tracker) 
     urlopen_result.read = minimock.Mock(
      'urlobj.read', tracker=self.tracker, returns='OMG') 
     foo.urllib2.urlopen = minimock.Mock(
      'urllib2.urlopen', tracker=self.tracker, returns=urlopen_result) 

     # Now when we call foo.bar(URL) and it invokes 
     # *urllib2.urlopen(URL).read()*, it will not actually send a request 
     # to URL, but will instead give us back the dummy response body 'OMG', 
     # which it then returns. 
     self.assertEquals(foo.bar('http://example.com/foo'), 'OMG') 

     # Now we can get trace info from minimock to verify that our mocked 
     # urllib2 was used as intended. self.tracker has traced our calls to 
     # *urllib2.urlopen()* 
     minimock.assert_same_trace(self.tracker, """\ 
Called urllib2.urlopen('http://example.com/foo) 
Called urlobj.read() 
Called urlobj.close()""") 

單元測試不應該是唯一的種種考驗你寫的雖然。如果您計劃在任何延長的時間段內維護此代碼,它們當然非常有用,IMO也非常重要。它們使重構變得更容易,並幫助捕捉迴歸,但它們並不真正測試各個組件之間的交互以及它們如何相互作用(如果你做對了)。

當我開始得到的地方,我有一個主要的成品體面的測試覆蓋率,我打算放開點,我喜歡寫運行在一個孤立的環境中完整的程序,至少一個集成測試。

我在當前的項目中已經取得了很多成功。我有大約80%的單元測試覆蓋率,其餘的代碼就像參數解析,命令調度和頂級應用程序狀態,這在單元測試中很難涵蓋。這個程序有很多外部依賴關係,碰到大約十幾種不同的Web服務,並且與大約6000臺機器進行交互,所以單獨運行這個程序確實很困難。

我最終編寫了一個集成測試,其中生成了一個用eventletwebob編寫的WSGI服務器,它模擬我的程序在生產中與之交互的所有服務。然後,集成測試猴子修補我們web service client library攔截所有的HTTP請求,並將它們發送到WSGI應用。完成之後,它會加載一個狀態文件,其中包含羣集狀態的序列化快照,並通過調用它的main()函數來調用該應用程序。現在,所有與我的程序交互的外部服務都是模擬的,這樣我就可以運行我的程序,因爲它將以可重複的方式在生產環境中運行。

0

要記住關於doctests的重要事情是,測試是基於字符串比較的,數字呈現爲字符串的方式會因不同的平臺甚至不同的python解釋器而有所不同。

我的大部分工作都涉及計算,所以我只使用doctests來測試我的例子和我的版本字符串。我在__init__.py中放了一些,因爲它會顯示爲我的epydoc生成的API文檔的首頁。

我使用鼻子進行測試,儘管我對檢查py.test的最新變化非常感興趣。