From 0c737e3de0fa5f68f6f1a3300ce4ebad55bf45e7 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Sun, 15 Dec 2013 22:15:15 +0000 Subject: [PATCH] Allow parameterised fixtures to give paramemter IDs This is just like the markers etc already can do. --- CHANGELOG | 3 +++ _pytest/python.py | 25 +++++++++++++++++-------- testing/python/fixture.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6e4f40be1..588e28bbf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ Unreleased ----------------------------------- +- Allow parameterized fixtures to specify the ID of the parameters by + adding an ids argument to pytest.fixture() and pytest.yield_fixture(). + - fix issue404 by always using the binary xml escape in the junitxml plugin 2.5.0 diff --git a/_pytest/python.py b/_pytest/python.py index b437871a7..913a3079e 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -35,11 +35,13 @@ def getimfunc(func): class FixtureFunctionMarker: - def __init__(self, scope, params, autouse=False, yieldctx=False): + def __init__(self, scope, params, + autouse=False, yieldctx=False, ids=None): self.scope = scope self.params = params self.autouse = autouse self.yieldctx = yieldctx + self.ids = ids def __call__(self, function): if inspect.isclass(function): @@ -49,7 +51,7 @@ class FixtureFunctionMarker: return function -def fixture(scope="function", params=None, autouse=False): +def fixture(scope="function", params=None, autouse=False, ids=None): """ (return a) decorator to mark a fixture factory function. This decorator can be used (with or or without parameters) to define @@ -71,6 +73,10 @@ def fixture(scope="function", params=None, autouse=False): can see it. If False (the default) then an explicit reference is needed to activate the fixture. + :arg ids: list of string ids each corresponding to the argvalues + so that they are part of the test id. If no ids are provided + they will be generated automatically from the argvalues. + """ if callable(scope) and params is None and autouse == False: # direct decoration @@ -78,9 +84,9 @@ def fixture(scope="function", params=None, autouse=False): "function", params, autouse)(scope) if params is not None and not isinstance(params, (list, tuple)): params = list(params) - return FixtureFunctionMarker(scope, params, autouse) + return FixtureFunctionMarker(scope, params, autouse, ids=ids) -def yield_fixture(scope="function", params=None, autouse=False): +def yield_fixture(scope="function", params=None, autouse=False, ids=None): """ (return a) decorator to mark a yield-fixture factory function (EXPERIMENTAL). @@ -94,7 +100,8 @@ def yield_fixture(scope="function", params=None, autouse=False): return FixtureFunctionMarker( "function", params, autouse, yieldctx=True)(scope) else: - return FixtureFunctionMarker(scope, params, autouse, yieldctx=True) + return FixtureFunctionMarker(scope, params, autouse, + yieldctx=True, ids=ids) defaultfuncargprefixmarker = fixture() @@ -1623,7 +1630,8 @@ class FixtureManager: for fixturedef in faclist: if fixturedef.params is not None: metafunc.parametrize(argname, fixturedef.params, - indirect=True, scope=fixturedef.scope) + indirect=True, scope=fixturedef.scope, + ids=fixturedef.ids) def pytest_collection_modifyitems(self, items): # separate parametrized setups @@ -1660,7 +1668,7 @@ class FixtureManager: fixturedef = FixtureDef(self, nodeid, name, obj, marker.scope, marker.params, yieldctx=marker.yieldctx, - unittest=unittest) + unittest=unittest, ids=marker.ids) faclist = self._arg2fixturedefs.setdefault(name, []) if fixturedef.has_location: faclist.append(fixturedef) @@ -1728,7 +1736,7 @@ def call_fixture_func(fixturefunc, request, kwargs, yieldctx): class FixtureDef: """ A container for a factory definition. """ def __init__(self, fixturemanager, baseid, argname, func, scope, params, - yieldctx, unittest=False): + yieldctx, unittest=False, ids=None): self._fixturemanager = fixturemanager self.baseid = baseid or '' self.has_location = baseid is not None @@ -1741,6 +1749,7 @@ class FixtureDef: self.argnames = getfuncargnames(func, startindex=startindex) self.yieldctx = yieldctx self.unittest = unittest + self.ids = ids self._finalizer = [] def addfinalizer(self, finalizer): diff --git a/testing/python/fixture.py b/testing/python/fixture.py index 60bbba342..79ae87cad 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -1989,6 +1989,40 @@ class TestFixtureMarker: reprec = testdir.inline_run() reprec.assertoutcome(passed=1) + def test_params_and_ids(self, testdir): + testdir.makepyfile(""" + import pytest + + @pytest.fixture(params=[object(), object()], + ids=['alpha', 'beta']) + def fix(request): + return request.param + + def test_foo(fix): + assert 1 + """) + res = testdir.runpytest('-v') + res.stdout.fnmatch_lines([ + '*test_foo*alpha*', + '*test_foo*beta*']) + + def test_params_and_ids_yieldfixture(self, testdir): + testdir.makepyfile(""" + import pytest + + @pytest.yield_fixture(params=[object(), object()], + ids=['alpha', 'beta']) + def fix(request): + yield request.param + + def test_foo(fix): + assert 1 + """) + res = testdir.runpytest('-v') + res.stdout.fnmatch_lines([ + '*test_foo*alpha*', + '*test_foo*beta*']) + class TestRequestScopeAccess: pytestmark = pytest.mark.parametrize(("scope", "ok", "error"),[