Reputation: 171
So I have a huge object that holds information that is being initiated inside a fixture. I need to use this information to run my tests and here starts the tricky part. IF I do not have an attribute inside the object that is being used inside the test case I have to skip it.
The fixture with the generation of the object is being initiated once before test runs (in general). I need an easy-to-use decorator/fixture/whatever before the test that will check if the object has what it is needed inside the object.
Example:
@pytest.fixture(scope="package")
def info(request):
print("Setting up...")
obj = Creator()
obj.setup()
obj.prepare() if hasattr(obj, "prepare") else ""
def teardown():
obj.teardown() if hasattr(obj, "teardown") else ""
request.addfinalizer(teardown)
return obj.call()
...
@has_attr("some_attr")
def test_sometest(info):
assert info.some_attr == 42
Upvotes: 4
Views: 2272
Reputation: 16855
There are several possibilities I can think of to achieve this, none of which looks as clean as your example.
The easiest one is just to do the skipping inside the test:
def test_something(info):
if not hasattr(info, "some_attr"):
pytest.skip("Missing attribute 'some_attr'")
assert info.some_attr == 42
Probably not what you want, but if you don't have many tests, it may make sense. If you have only a few different attributes you want to check, you can make specific fixtures for these attributes:
@pytest.fixture
def info_with_some_attr(info):
if not hasattr(info, "some_attr"):
pytest.skip("Missing attribute 'some_attr'")
yield info
def test_something(info_with_some_attr):
assert info_with_some_attr.some_attr == 42
If you have more attributes, you can parametrize the fixture with the attribute names instead:
@pytest.fixture
def info_with_attr(request, info):
if hasattr(request, "param"):
for attr in request.param:
if not hasattr(info, attr):
pytest.skip(f"Missing attribute '{attr}'")
yield info
@pytest.mark.parametrize("info_with_attr", [("some_attr", "another_attr")], indirect=True)
def test_something(info_with_attr):
assert info_with_attr.some_attr == 42
This does exactly what you want, although it looks a bit awkward.
Edit: Updated the last example to use a tuple instead of single string, as mentioned in the comments.
Upvotes: 6