unittest使用過程中sys.exit(not self.result.wasSuccessful())

起因:

在運行下面的unittest過程中出現了個Traceback:

被測試腳本:

# splitter.py
def split(line, types=None, delimiter=None):
    """Splits a line of test and optionally performs type conversion.
    For example:

    >>> split('GOOD 100 490.50')
    ['GOOD', '100', '490.50']
    >>> split('GOOD 100 490.50', [str, int, float])
    ['GOOD', 100, 490.50]
    >>>
    By default, splitting is perfomed on whitespace, but a different delimiter
    can be selected with the delimiter keyword argument:

    >>> split('GOOD, 100, 490.50', delimiter=',')
    ['GOOOD', '100', '490.50']
    >>>
    """

    fields = line.split(delimiter)
    if types:
        fields = [ty(val) for ty, val in zip(types, fields)]
    return fields

if __name__ == '__main__':
    # test myself
    import doctest
    doctest.testmod()

 測試腳本:

# testsplitter.py
import splitter
import unittest

# unit test
class TestSplitFunction(unittest.TestCase):
    def setUp(self):
        pass
    def tearDown(self):
        pass
    def testsimplestring(self):
        r = splitter.split('GOOD 100 490.50')
        self.assertEqual(r, ['GOOD', '100', '490.50'])
    def testypeconvert(self):
        r = splitter.split('GOOD 100 490.50', [str, int, float])
        self.assertAlmostEqual(r, ['GOOD', 100, 490.50])
    def testdelimiter(self):
        r = splitter.split('GOOD,100,490.50', delimiter=',')
        self.assertEqual(r, ['GOOD', '100', '490.50'])

# Run unit test
if __name__ == '__main__':
    unittest.main()

 結果:

...
----------------------------------------------------------------------
Ran 3 tests in 0.011s

OK
Traceback (most recent call last):
  File "C:\Users\Administrator\Desktop\Python Scripts\testsplitter - 副本.py", line 23, in <module>
    unittest.main()
  File "D:\Python33\lib\unittest\main.py", line 125, in __init__
    self.runTests()
  File "D:\Python33\lib\unittest\main.py", line 267, in runTests
    sys.exit(not self.result.wasSuccessful())
SystemExit: False
>>> ================================ RESTART ================================
>>> 
...
----------------------------------------------------------------------
Ran 3 tests in 0.011s

OK
Traceback (most recent call last):
  File "C:\Users\Administrator\Desktop\Python Scripts\testsplitter - 副本.py", line 23, in <module>
    unittest.main()
  File "D:\Python33\lib\unittest\main.py", line 125, in __init__
    self.runTests()
  File "D:\Python33\lib\unittest\main.py", line 267, in runTests
    sys.exit(not self.result.wasSuccessful())
SystemExit: False

 從結果看,所有測試用例是都通過的,但是出現了Traceback,SystemExit: False.

分析:

查找到的鏈接: http://bugs.python.org/issue2821

這是一個IDLE問題

IDLE catches the SystemExit function raised by TestProgram().runTests()
and prints the traceback. Not a bug in unittest.

因爲unittest.main()函數會調用sys.exit()來結束函數進程。使用的參數就是not self.result.wasSuccessful()

進一步分析:

那如果是assert過程中出現fail,會是什麼樣?

修改測試腳本:

# testsplitter.py
import splitter
import unittest

# unit test
class TestSplitFunction(unittest.TestCase):
    def setUp(self):
        pass
    def tearDown(self):
        pass
    def testsimplestring(self):
        r = splitter.split('GOOD 100 490.50')
        self.assertEqual(r, ['GOOD', '100', '490.50'])
    def testypeconvert(self):
        r = splitter.split('GOOD 100 490.50', [str, int, float])
        self.assertAlmostEqual(r, ['GOOD', 10, 490.50])  # Modify this line
    def testdelimiter(self):
        r = splitter.split('GOOD,100,490.50', delimiter=',')
        self.assertEqual(r, ['GOOD', '100', '490.50'])

# Run unit test
if __name__ == '__main__':
    unittest.main()

 運行結果:

..E
======================================================================
ERROR: testypeconvert (__main__.TestSplitFunction)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\Administrator\Desktop\Python Scripts\testsplitter - 副本.py", line 16, in testypeconvert
    self.assertAlmostEqual(r, ['GOOD', 10, 490.50])
  File "D:\Python33\lib\unittest\case.py", line 683, in assertAlmostEqual
    if round(abs(second-first), places) == 0:
TypeError: unsupported operand type(s) for -: 'list' and 'list'

----------------------------------------------------------------------
Ran 3 tests in 0.077s

FAILED (errors=1)
Traceback (most recent call last):
  File "C:\Users\Administrator\Desktop\Python Scripts\testsplitter - 副本.py", line 23, in <module>
    unittest.main()
  File "D:\Python33\lib\unittest\main.py", line 125, in __init__
    self.runTests()
  File "D:\Python33\lib\unittest\main.py", line 267, in runTests
    sys.exit(not self.result.wasSuccessful())
SystemExit: True

 

分析:

unittest裏面的assert和一般的assert是不一樣的,即使fail了,其實還是會繼續執行其他的測試用例,不會立即跳出函數。最後跳出函數還是調用sys.exit(),只不過這個時候的參數就是True了。

類似sys.exit(1) - 表示非正常退出。在unittest裏面表示有測試用例失敗。

sys.exist(0) - 正常退出。在unittest裏面表示測試用例均通過。

 

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