Context
I have a test class where all my tests inherit from. It cant run by itself as it really doesnt contain any setup info
I wanted to add a test which is executed by ALL tests (adding it to the baseclass seems logical)
But now I notice the basetestclass( => Foo) which I import is being detected as a test itself and runs and is visible in the reports
Code
the base class in base.py
from unittest import TestCase
class Foo(TestCase):
@classmethod
def setUpClass(cls):
# prepare the generic setup stuff based on what is defined in the child class
print("setupclass Foo done")
def test_run_in_all_inherited_tests(self):
print("fooBar")
assert True
the real test in test_something.py
from base import Foo # <= This is being detected as a testclass object and thus will be executed
class TestFoo(Foo):
@classmethod
def setUpClass(cls):
# define specific test setup
super().setUpClass()
print("setup TestFoo done")
def test_pass(self):
pass
def test_assert(self):
assert False
This triggers a testrun of the imported Foo
The Question
How can I import Foo without that its being detected as a 'test' If I remove the test to run in all tests all is fine.
Adding @nottest
decorator to Foo wont work since then also all inherited classes are defined nottest.
It needs to run on nose
, pytest
and unittest
testrunners
I noticed if I changed the import statement like below that it also works. But that would mean adjusting a few hundreds of testfiles in different repos. (I'd like to avoid that)
import base
class TestFoo(base.Foo):
CodePudding user response:
The key to the answer seems to be that each test has an attribute __test__
which is set to True
when it is a test.
Setting it to False
when the class should not be a test will then let the test collector ignore this class.
The answer assumes I can only do changes in the base.py
In python 3.9 classmethod and property decorators can be combined so I wrote a separate answer for that
answer for < py3.9
the base class in base.py
from unittest import TestCase
class MetaFoo(type):
@property
def __test__(cls):
return cls != Foo
class Foo(TestCase, metaclass=MetaFoo):
@classmethod
def setUpClass(cls):
# prepare the generic setup stuff based on what is defined in the child class
print("setupclass Foo done")
def test_run_in_all_inherited_tests(self):
print("fooBar")
assert True
answer for >= py3.9
the base class in base.py
from unittest import TestCase
class Foo(TestCase):
@classmethod
@property
def __test__(cls):
return cls != Foo
@classmethod
def setUpClass(cls):
# prepare the generic setup stuff based on what is defined in the child class
print("setupclass Foo done")
def test_run_in_all_inherited_tests(self):
print("fooBar")
assert True
the actual test
test_something.py
from base import Foo # <= This will not be detected as a test anymore as __test__ returns False
class TestFoo(Foo):
@classmethod
def setUpClass(cls):
# define specific test setup
super().setUpClass()
print("setup TestFoo done")
def test_pass(self):
pass
def test_assert(self):
assert False