Need a bit of help correcting a decorator for unittest. I'm not sure how to meet the requirements of unit test. The idea of this decorator is to mark the test as an expectedFailure IF True is passed in. Otherwise allow the test to simply run. This decorator works for test functions but doesn't work for class definitions
import unittest
def expectedFailureIf(expFailure):
if expFailure:
return unittest.expectedFailure
return lambda func: func
@expectedFailureIf(GetCurrentOS() == kPlatMac) # Fails on Class
class someClass(unittest.TestCase):
#@expectedFailureIf(GetCurrentOS() == kPlatMac) # Works on Function
def test_sometestA(self):
assert True
def test_sometestB(self):
assert False
The error that I'm getting is test_sometest() takes exactly 1 argument. Removing the decorator allows the test to run. Moving the decorator to top of function allows the test to run.
History... One of my platforms works fine and the other platform does not. I want to allow one platform to run all the tests while the other platform will be marked as expected failures. Of course I do not want to use skip or skip if. Since that won't allow the valid platform to run. Marking them as expected failure will also not work since one platform will return unexpected success. With the expectedFailureIf() in place each platform will correctly report and once things are fixed these tests will report as unexpected success. Which will notify ME when things are fixed. For me... this seems a better outcome.
On Python 3 your code is working fine. The implementation of unittest.expectedFailure
is better there, and it works correctly when decorating on either classes or functions.
On Python 2, the unittest.expectedFailure
is only designed to work on functions.
Here's a replacement which works on Python 2.
import inspect
import types
import unittest
def expectedFailureIf(condition):
if callable(condition):
condition = condition()
if not condition:
# return identity function for no-op
return lambda x: x
def patch(func_or_class):
if isinstance(func_or_class, types.FunctionType):
return unittest.expectedFailure(func_or_class)
for name, member in inspect.getmembers(func_or_class):
if name.startswith('test') and isinstance(member, types.MethodType):
setattr(func_or_class, name, unittest.expectedFailure(member))
return func_or_class
return patch
@expectedFailureIf(True)
class MyTest(unittest.TestCase):
def test_that_passes(self):
assert 2 + 2 == 4
def test_that_fails(self):
assert 2 + 2 == 5
if __name__ == "__main__":
unittest.main(verbosity=2)
Result:
test_that_fails (__main__.MyTest) ... expected failure
test_that_passes (__main__.MyTest) ... unexpected success
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK (expected failures=1, unexpected successes=1)
The fact that an unexpected success doesn't fail the test run is a bug in Python! It was addressed back in Jan 2014 (Python 3.4), but this bugfix was not merged into 2.7's branch due to backwards compatibility concerns (see the comments on issue20165). So, that's now a Python 2 "feature", unfortunately.
If this is a deal-breaker to you, consider upgrading to a more recent Python version and/or using a better test runner.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With