Python 单元测试:使 AssertionError 成为错误而不是失败
Python unittest: make AssertionError an error instead of a failure
Python 2.7。 The unittest doc 说:
To make migrating existing test suites easier, unittest supports tests raising AssertionError to indicate test failure. However, it is recommended that you use the explicit TestCase.fail*() and TestCase.assert*() methods instead, as future versions of unittest may treat AssertionError differently.
我在测试代码中使用了很多 assert
语句,但这些断言的失败实际上应该是测试错误(即 "code did not run properly with those inputs")而不是失败(即 "code gave incorrect output").
我可以看到以下可能的解决方案:
- 重写测试代码以抛出更好类型的异常
- 将除测试断言本身 (
self.assertSomething(...)
) 之外的所有测试方法包装在 try...except AssertionError: raise SomeOtherException
块中
- 更改单元测试的行为,使其考虑这些错误而不是失败。
选项 1 会花费一些时间,选项 2 感觉很老套;选项 3 对我来说是最好的,但它可用吗? (以防万一:不,我不能切换到 Python 3.)我在网上看不到任何东西,但很难使用特定的关键字。
MWE:
import unittest
def add_one_to_int(a):
assert isinstance(a, int)
return a + 1
class TestAddOne(unittest.TestCase):
def test_one_plus_one_is_three(self):
# This tests fails with
# AssertionError: 2 != 3
# which is fine
self.assertEqual(add_one_to_int(1), 3)
def test_add_one_to_str(self):
# This tests fails with
# AssertionError
# when I would rather have it an error
add_one_to_int('some string')
if __name__ == '__main__':
unittest.main(verbosity=2) # 2 failures instead of 1 failure, 1 error
我认为选项 3 可以通过 class 属性 "failureException" 实现,正如 Python 2.7:
的单元测试文档中所定义的
failureException:
This class attribute gives the exception raised by the test method. If a test framework needs to use a specialized exception, possibly to carry additional information, it must subclass this exception in order to “play fair” with the framework. The initial value of this attribute is AssertionError.
例如:
import unittest
class MyException(Exception):
pass
class MyUnitTest(unittest.TestCase):
failureException = MyException
def add_one_to_int(a):
assert isinstance(a, int)
return a + 1
class TestAddOne(MyUnitTest): # <--------- See above
def test_one_plus_one_is_three(self):
# This tests fails with
# AssertionError: 2 != 3
# which is fine
self.assertEqual(add_one_to_int(1), 3)
def test_add_one_to_str(self):
# This tests fails with
# AssertionError
# when I would rather have it an error
add_one_to_int('some string')
if __name__ == '__main__':
unittest.main(verbosity=2) # ------> FAILED (failures=1, errors=1)
Python 2.7。 The unittest doc 说:
To make migrating existing test suites easier, unittest supports tests raising AssertionError to indicate test failure. However, it is recommended that you use the explicit TestCase.fail*() and TestCase.assert*() methods instead, as future versions of unittest may treat AssertionError differently.
我在测试代码中使用了很多 assert
语句,但这些断言的失败实际上应该是测试错误(即 "code did not run properly with those inputs")而不是失败(即 "code gave incorrect output").
我可以看到以下可能的解决方案:
- 重写测试代码以抛出更好类型的异常
- 将除测试断言本身 (
self.assertSomething(...)
) 之外的所有测试方法包装在try...except AssertionError: raise SomeOtherException
块中 - 更改单元测试的行为,使其考虑这些错误而不是失败。
选项 1 会花费一些时间,选项 2 感觉很老套;选项 3 对我来说是最好的,但它可用吗? (以防万一:不,我不能切换到 Python 3.)我在网上看不到任何东西,但很难使用特定的关键字。
MWE:
import unittest
def add_one_to_int(a):
assert isinstance(a, int)
return a + 1
class TestAddOne(unittest.TestCase):
def test_one_plus_one_is_three(self):
# This tests fails with
# AssertionError: 2 != 3
# which is fine
self.assertEqual(add_one_to_int(1), 3)
def test_add_one_to_str(self):
# This tests fails with
# AssertionError
# when I would rather have it an error
add_one_to_int('some string')
if __name__ == '__main__':
unittest.main(verbosity=2) # 2 failures instead of 1 failure, 1 error
我认为选项 3 可以通过 class 属性 "failureException" 实现,正如 Python 2.7:
的单元测试文档中所定义的failureException: This class attribute gives the exception raised by the test method. If a test framework needs to use a specialized exception, possibly to carry additional information, it must subclass this exception in order to “play fair” with the framework. The initial value of this attribute is AssertionError.
例如:
import unittest
class MyException(Exception):
pass
class MyUnitTest(unittest.TestCase):
failureException = MyException
def add_one_to_int(a):
assert isinstance(a, int)
return a + 1
class TestAddOne(MyUnitTest): # <--------- See above
def test_one_plus_one_is_three(self):
# This tests fails with
# AssertionError: 2 != 3
# which is fine
self.assertEqual(add_one_to_int(1), 3)
def test_add_one_to_str(self):
# This tests fails with
# AssertionError
# when I would rather have it an error
add_one_to_int('some string')
if __name__ == '__main__':
unittest.main(verbosity=2) # ------> FAILED (failures=1, errors=1)