2012-05-03 59 views
1

背景Python的單元測試:該測試方法

我試圖找出如何運行鍼對多個輸入值的單個單元測試,然後顯示失敗內響應失敗。這是諸如此類的事情的一個微不足道的演示中,我心裏有:

from time import time 
import unittest 

def demo(): 
    while True: 
     count = 0 
     for i in xrange(10): 
      count += 1 
      yield int(time() * 1000) + count 
     count = 0 

class TestDemo(unittest.TestCase): 
    def setUp(self): 
     self.gen = demo() 
     self.prev = next(self.gen) 

    def test_always_bigger(self): 
     for cycle in xrange(1000): 
      curr = next(self.gen) 
      self.assertGreater(curr, self.prev) 
      self.prev = curr 

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

最類似的問題我已經找到了回答一些動態test_<something>方法創建的(例如:123)或nose generators(例如:1,2)。我期望基於不可預知的輸入運行1000次迭代,同時堅持使用標準庫,因此這兩種解決方案都非常適合。簡單的循環(如上所示)適用於兩個限制:對於複雜的輸入,記錄導致測試失敗的原因不足(我真正的問題);並且,在整個測試中,在方法test_<...>中的單個失敗失敗。

問題

我可以與早期失效生活,但我怎麼能在投入獲取引起故障,而無需創建數以千計的成功輸出的行?

非回答

我試過assert...方法msg kwarg,但它確實只是很適合那種瑣碎的情況下,庫中已經處理好。在上面的例子中,unittest知道顯示導致斷言失敗的兩個long。我可以對它進行註釋,並通過self.assertGreater(curr,self.prev,msg =「cycle%s」%cycle)提供很多洞察,但是在assertDictEquals上顯示深度嵌套的字典是一團糟。

令人滿意的解決方案

answer顯示了一個有趣的使用記錄模塊,但會產生數以千計的輸出線的每一個成功的測試。在測試方法中是否有可能檢測到故障?喜歡的東西:

def test_always_bigger(self): 
     for cycle in xrange(1000): 
      curr = next(self.gen) 
      fail = self.assertGreater(curr, self.prev) 
      if fail: 
       log.debug('...') 
      self.prev = curr 

回答

2
def test_always_bigger(self): 
    for cycle in xrange(1000): 
     curr = next(self.gen) 
     try: 
      self.assertGreater(curr, self.prev) 
     except AssertionError: # raised by TestCase.fail, called by all asserts 
      log.debug('...') 
      raise 
     self.prev = curr 

這實現了在失敗的情況下記錄的語義,然後與故障不斷。如果要完成所有的測試,我將做到以下幾點:

def test_always_bigger(self): 
    ex = None 
    for cycle in xrange(1000): 
     curr = next(self.gen) 
     try: 
      self.assertGreater(curr, self.prev) 
     except AssertionError, ae: 
      ex = ae # just remember it 
      log.debug('...') 
     self.prev = curr 
    if ex: 
     raise ex 

顯然,這隻會提高第一AssertionError,但它會運行到完成,將獨立記錄所有故障。由於這個函數只代表框架的一個測試,所以你不能真正產生多個錯誤。

如果您需要訪問所有的異常出於某種原因,你可能能夠逃脫以下(不與unittest徹底的測試)

def test_always_bigger(self): 
    exes = [] 
    for cycle in xrange(1000): 
     curr = next(self.gen) 
     try: 
      self.assertGreater(curr, self.prev) 
     except AssertionError, ae: 
      exes.append(ae) 
      log.debug('...') 
     self.prev = curr 
    if exes: 
     self.fail(exes) 
     # if that doesn't work, try: raise AssertionError(exes)