问题
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.
回答1:
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.
回答2:
You can use pytest parameterization to pass multiple arguments to the same test, in this case, the argument would most likely be the class being tested.
来源:https://stackoverflow.com/questions/46040478/how-to-test-a-class-inherited-methods-in-pytest