JL Peyret
JL Peyret

Reputation: 12204

Can I "turn-off" @unittest.expectedFailure?

Let's say that, for whatever reason, I want to write a set of test cases that start out from the premise of failing code.

Maybe because setting up a failure is really complicated, while the demonstrating a fixed state is simple. In my case, it's not even that, I wanted to start with a failed test and then show how to fix it, for documentation purposes.

I can decorate @unittest.expectedFailure on the base class.

But the the fixed subclasses blow up with unexpected success because the decoration is inherited.

Can I remove the expectedFailure somehow?

import sys
import unittest

@unittest.expectedFailure
class Test_ThisShouldFail(unittest.TestCase):
    """ for argument's sake, let's say 
    the configuration and testing is very complicated 
    and I want it fail by default.
    Subclasses fix the issue but re-use the test code
    """

    data = dict(a=1, b=2)

    def test_evens(self):
        for key, v in self.data.items():
            self.assertFalse(v % 2, f"{key}:Odd on {v}")

#@ 👉???unittest.expectedSuccess???? 
class Test_ThisShouldWork(Test_ThisShouldFail):
    """ how do I turn off the expected failure? """

    def setUp(self):
        self.data.update(a=10)

if __name__ == "__main__":
    sys.exit(unittest.main())

output:

FAILED (expected failures=1, unexpected successes=1)
(venv) @explore$ py test_expectedfail.py -v
test_evens (__main__.Test_ThisShouldFail) ... expected failure
test_evens (__main__.Test_ThisShouldWork) ... unexpected success

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (expected failures=1, unexpected successes=1)

this didn't work:

I was hoping the MRO would look at TurnItOff's blank unittest settings and use them. No such luck.

class TurnItOff(unittest.TestCase):
    pass

class Test_ThisShouldWork(TurnItOff, Test_ThisShouldFail):
    ....

Upvotes: 1

Views: 160

Answers (1)

MrBean Bremen
MrBean Bremen

Reputation: 16855

This relies on the internal implementation of unittest.expectedFailure, but works for a start:

def expectedSuccess(test_item):
    test_item.__unittest_expecting_failure__ = False
    return test_item


@unittest.expectedFailure
class TestFailure(unittest.TestCase):
    def test_something(self):
        self.assertTrue(False)


@expectedSuccess
class TestSuccess(TestFailure):
    def test_something(self):
        self.assertTrue(True)

Note that test_item can be both a class or a function, depending on where you put the decorator.

Upvotes: 1

Related Questions