2014-09-25 63 views
1

我正在使用Python的(3.4.1)unittest模塊進行單元測試。Python 3 unittest:如何提取測試結果?

我使用進口加載所有我的測試模塊文件,然後運行unittest.main():

import unittest 
import testing_module1 
import testing_module2 
# [...] 
if __name__ == '__main__': 
    unittest.main() 

這工作完全適合我,因爲它是簡單的,並尊重我用來控制冗長的命令行參數或哪些測試運行。

我想繼續輸出相同的信息,但我想從結果中生成一個XML文件。我試過xmlrunner(https://github.com/xmlrunner/unittest-xml-reporting/)但是:

  • 它不會像標準運行器那樣向stdout輸出儘可能多的信息;
  • 它使用特定格式的XML,不適合我。

我想用我需要的格式生成XML(我不介意手動操作),但對測試的運行方式做了最小的更改。

我有什麼選擇?

  1. 我可以編寫自己的TestRunner,但我不想重寫所有內容,我只是想用最少的代碼更改將額外的輸出添加到實際運行程序中。
  2. 我可以繼承unittest.TextTestRunner,但我擔心向它添加XML輸出將需要重寫每一個方法,首先會喪失繼承的優勢。
  3. 我可以嘗試在撥打unittest.main()之後提取測試結果並解析它。這裏的問題在於,unittest.main()似乎在完成後退出,因此它後面的任何代碼都未執行。

有什麼建議嗎?

謝謝!

回答

0

這是如何工作的。在StringIO中捕獲到unit.stderr的unittest的輸出。在unittest.main後面加入`exit = False'繼續。根據需要閱讀捕獲的輸出和處理過程。概念證明:

import contextlib 
import io 
import sys 
import unittest 

class Mytest(unittest.TestCase): 
    def test_true(self): 
     self.assertTrue(True) 

@contextlib.contextmanager 
def err_to(file): 
    old_err = sys.stderr 
    sys.stderr = file 
    yield 
    sys.stderr = old_err 

if __name__ == '__main__': 
    result = io.StringIO() 
    with err_to(result): 
     unittest.main(exit=False) 
    result.seek(0) 
    print(result.read()) 

這版畫(sys.stdout來)

---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

OK 

注:contextlib有redirect_stdout,但不redirect_stderr的。以上更簡單的是contextlib代碼。上面假設沒有沒有被unittest捕獲的例外。請參閱contextlib.contextmanager文檔以添加try:except:finally。我把它留給你。

+0

謝謝,這是一條有趣的路徑。但我需要在測試中存儲更多的信息,而不是屏幕上顯示的信息。分析可能是相當單調乏味的... – 2014-10-22 20:08:08

1

我最終編寫了兩個新類,它們繼承自unittest.TextTestResultunittest.TextTestRunner。這樣一來,我可以運行主要那樣:

unittest.main(testRunner=xmlrunner.XMLTestRunner(...)) 

我重載unittest.TextTestRunner__init__和來自unittest.TextTestResult

  • addSuccess()
  • addError()
  • addFailure()
  • addSubTest()

例如:

def addSuccess(self, test): 
    super().addSuccess(test) 
    [... store the test into list, dictionary, whatever... ] 

由於這些add*()函數被調用的實際測試中,我可以將它們存儲在一個全局列表,並在我的XMLTestRunner.run()結束它們解析:

def run(self, test): 
    result = super().run(test) 
    self.save_xml_report(result) 
    return result 

請注意,這些功能通常在/usr/lib/python3.4/unittest/runner.py中定義。

警告注意:通過使用一個實際的對象傳遞unittest.main()testRunner參數如圖所示,推出蟒蛇時給出的命令行參數被忽略。例如,使用-v參數增加詳細級別將被忽略。這是因爲在/usr/lib/python3.4/unittest/main.py中定義的TestProgram類會檢測unittest.main()是否以testRunner作爲類或對象運行(請參閱文件末尾附近的runTests())。如果你只給出這樣一個類:

unittest.main(testRunner=xmlrunner.XMLTestRunner) 

然後命令行參數被解析。但是你傳遞一個實例化的對象(就像我需要的那樣),runTests()就會按原樣使用它。因此我不得不在自己的解析參數XMLTestRunner.__init__()

# Similar to what /usr/lib/python3.4/unittest/main.py's TestProgram._getParentArgParser() does. 
import argparse 
parser = argparse.ArgumentParser(add_help=False) 
parser.add_argument('-v', '--verbose', dest='verbosity', 
        action='store_const', const=2, default=1, # Add default=1, not present in _getParentArgParser() 
        help='Verbose output') 
parser.add_argument('-q', '--quiet', dest='verbosity', 
        action='store_const', const=0, 
        help='Quiet output') 
parser.add_argument('-f', '--failfast', dest='failfast', 
        action='store_true', 
        help='Stop on first fail or error') 
parser.add_argument('-c', '--catch', dest='catchbreak', 
        action='store_true', 
        help='Catch ctrl-C and display results so far') 
parser.add_argument('-b', '--buffer', dest='buffer', 
        action='store_true', 
        help='Buffer stdout and stderr during tests') 
+0

有可能獲得更多的信息,你如何做覆蓋?這正是我需要弄清楚如何去做的事情,但我不確定如何實現。 – 2016-07-18 12:34:36

+0

你的意思是'addSuccess()'和co。嗎?這只是繼承;子類的方法將優先於父類的方法... – 2016-07-19 13:21:21

相關問題