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

时间:2022-06-20 20:04:02

起因:

在运行下面的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里面表示测试用例均通过。