house.py
:
class House:
def is_habitable(self):
return True
def is_on_the_ground(self):
return True
conftest.py
:
import pytest
from house import House
@pytest.fixture(scope='class')
def house():
return House()
test_house.py
:
class TestHouse:
def test_habitability(self, house):
assert house.is_habitable()
def test_groundedness(self, house):
assert house.is_on_the_ground()
Up to that point, everything is being tested.
Now I add a subclass and override a method in house.py
:
class House:
def is_habitable(self):
return True
def is_on_the_ground(self):
return True
class TreeHouse(House):
def is_on_the_ground(self):
return False
I also add a new fixture for that class in conftest.py
:
import pytest
from house import House
from house import TreeHouse
@pytest.fixture(scope='class')
def house():
return House()
@pytest.fixture(scope='class')
def tree_house():
return TreeHouse()
I add a new test class for tree house in test_house.py
:
class TestHouse:
def test_habitability(self, house):
assert house.is_habitable()
def test_groundedness(self, house):
assert house.is_on_the_ground()
class TestTreeHouse:
def test_groundedness(self, tree_house):
assert not tree_house.is_on_the_ground()
At that point, the code works, but there are cases that are not tested. For example, to be complete, I would need to test again the methods inherited from House
in TreeHouse
.
Rewriting the same tests from the TestHouse
would not be DRY.
How do I test the inherited method of TreeHouse
(in this case is_habitable
) without duplicating code?
I would like something like re-testing the TreeHouse
with the same tests that its super class runs through, but not for the methods / properties that are new or overridden.
After some research I came across contradictory sources. And after digging in the pytest documentation I fail to understand what applies to this scenario.
I am interested in the pytest way to do this. Please reference the docs and explain how that applies here.
One way to do this would be to use the fixture name house
for all test methods (even if it's testing a TreeHouse
), and override its value in each test context:
class TestTreeHouse(TestHouse):
@pytest.fixture
def house(self, tree_house):
return tree_house
def test_groundedness(self, house):
assert not house.is_on_the_ground()
Also note TestTreeHouse
inherits from TestHouse
. Since pytest merely enumerates methods of classes (i.e. there is no "registration" done with, say, a @pytest.test()
decorator), all tests defined in TestHouse
will be discovered in subclasses of it, without any further intervention.
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