Skip to content

Instantly share code, notes, and snippets.

@wcooley
Last active April 3, 2023 14:35
Show Gist options
  • Save wcooley/7472b8de6edb1e8ceda560843c0519a8 to your computer and use it in GitHub Desktop.
Save wcooley/7472b8de6edb1e8ceda560843c0519a8 to your computer and use it in GitHub Desktop.
Pytest: Ab(using) parametrize to alias long fixture names

Problem

I am testing an object with varied datasets, which I am creating as separate fixtures, so my fixture names become rather long due to encoding enough distinguishing characteristics so I can keep their purposes straight. I have to refer to my object a number of times throughout the test and futhermore there is a local convention for the name of the object in production code, so it makes sense to use the same short name in my tests. As a result, one of the very first things I do in the test is alias the long fixture name to the short conventional name, as can be seen in the assignment to foo in test_01_before.py. Whenever I do this, I wish to myself "it's too bad there isn't a way to express the fixture declaration/import with an alias like one can do with a from ... import ... as ... statement.

Idea

We can use the pytest.mark.parametrize facility to alias the fixture to a more appropriate name (with help from the pytest-lazy-fixture plugin, which allows us to refer to the fixture with a string), as seen in the @pytest.mark.parametrize line in test_02_alias.py. And because the calls to parametrize stack, we can declare multiple fixtures that way.

Is this crazy, beautiful, hideous or lazy?

Further

We could pre-create the parametrize instance with the aliased fixture and use that as a mark to apply to the test directly, as can be seen in test_03_alias.py. The problem with this approach is that we have removed the alias name from the test where the alias is used, which might be OK if we are confident that we will know what the alias should be called, although it sounds like too much of a special case that would be easily forgotten.

Instead, we can implement a factory function (which we might package up into a plug-in) that would handle creating the parametrize instance, as we have done with use_fixture_as in test_04_alias.py.

import pytest
@pytest.fixture
def sample_foo_with_bar1_and_baz2():
return 'fixture_with_a_very_long_name'
def test_foo_with_bar1_and_baz2(sample_foo_with_bar1_and_baz2):
# In reality, 'foo' is a more complicated datatype and is
# referred to many more times in the test
foo = sample_foo_with_bar1_and_baz2
assert 'fixture_with_a_very_long_name' == foo
# Requires `pytest-lazy-fixture`
import pytest
@pytest.fixture
def sample_foo_with_bar1_and_baz2():
return 'fixture_with_a_very_long_name'
@pytest.mark.parametrize('foo',
[pytest.lazy_fixture('sample_foo_with_bar1_and_baz2')])
def test_foo_with_bar1_and_baz2(foo):
assert 'fixture_with_a_very_long_name' == foo
# Requires `pytest-lazy-fixture`
import pytest
@pytest.fixture
def sample_blob_with_biz3_and_bam5():
return 'blob_biz3_bam5'
pytest.mark.sample_blob_with_biz3_and_bam5 = \
pytest.mark.parametrize('blob', [pytest.lazy_fixture('sample_blob_with_biz3_and_bam5')])
@pytest.mark.sample_blob_with_biz3_and_bam5
def test_foo_with_bar1_and_baz2(blob):
assert 'biz3' in blob
# Requires `pytest-lazy-fixture`
import pytest
def use_fixture_as(fixture_alias, fixture_name):
return pytest.mark.parametrize([fixture_alias],
[(pytest.lazy_fixture(fixture_name),)],
ids=[fixture_alias])
# Imagine this were an actual plugin
pytest.use_fixture_as = use_fixture_as
@pytest.fixture
def sample_blob_with_biz3_and_bam5():
return 'blob_biz3_bam5'
@pytest.use_fixture_as('blob', 'sample_blob_with_biz3_and_bam5')
def test_foo_with_bar1_and_baz2(blob):
assert 'biz3' in blob
@wcooley
Copy link
Author

wcooley commented May 15, 2020

Interesting approach! It had not occurred to me to try manipulating the function signature directly; I have used inspect but I guess I assumed much of that was read-only (or, at least, that modifying was an undefined operation and not reliable).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment