Skip to content

Commit

Permalink
Fix scope determination with indirect parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoddemus committed Sep 15, 2018
1 parent 49800ea commit b1e5bde
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 5 deletions.
1 change: 1 addition & 0 deletions changelog/3941.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix scope determination of parametrized, indirect fixtures when other fixtures are used in the same test function.
15 changes: 10 additions & 5 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -1141,13 +1141,18 @@ def _find_parametrized_scope(argnames, arg2fixturedefs, indirect):
"""
from _pytest.fixtures import scopes

indirect_as_list = isinstance(indirect, (list, tuple))
all_arguments_are_fixtures = (
indirect is True or indirect_as_list and len(indirect) == argnames
)
if isinstance(indirect, (list, tuple)):
all_arguments_are_fixtures = len(indirect) == len(argnames)
else:
all_arguments_are_fixtures = bool(indirect)

if all_arguments_are_fixtures:
fixturedefs = arg2fixturedefs or {}
used_scopes = [fixturedef[0].scope for name, fixturedef in fixturedefs.items()]
used_scopes = [
fixturedef[0].scope
for name, fixturedef in fixturedefs.items()
if name in argnames
]
if used_scopes:
# Takes the most narrow scope from used fixtures
for scope in reversed(scopes):
Expand Down
79 changes: 79 additions & 0 deletions testing/python/metafunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,52 @@ def func(x):
except ValueError as ve:
assert "has an unsupported scope value 'doggy'" in str(ve)

def test_find_parametrized_scope(self):
"""unittest for _find_parametrized_scope (#3941)"""
from _pytest.python import _find_parametrized_scope

@attr.s
class DummyFixtureDef(object):
scope = attr.ib()

fixtures_defs = dict(
session_fix=[DummyFixtureDef("session")],
package_fix=[DummyFixtureDef("package")],
module_fix=[DummyFixtureDef("module")],
class_fix=[DummyFixtureDef("class")],
func_fix=[DummyFixtureDef("function")],
)

# use arguments to determine narrow scope; the cause of the bug is that it would look on all
# fixture defs given to the method
def find_scope(argnames, indirect):
return _find_parametrized_scope(argnames, fixtures_defs, indirect=indirect)

assert find_scope(["func_fix"], indirect=True) == "function"
assert find_scope(["class_fix"], indirect=True) == "class"
assert find_scope(["module_fix"], indirect=True) == "module"
assert find_scope(["package_fix"], indirect=True) == "package"
assert find_scope(["session_fix"], indirect=True) == "session"

assert find_scope(["class_fix", "func_fix"], indirect=True) == "function"
assert find_scope(["func_fix", "session_fix"], indirect=True) == "function"
assert find_scope(["session_fix", "class_fix"], indirect=True) == "class"
assert find_scope(["package_fix", "session_fix"], indirect=True) == "package"
assert find_scope(["module_fix", "session_fix"], indirect=True) == "module"

# when indirect is False or is not for all scopes, always use function
assert find_scope(["session_fix", "module_fix"], indirect=False) == "function"
assert (
find_scope(["session_fix", "module_fix"], indirect=["module_fix"])
== "function"
)
assert (
find_scope(
["session_fix", "module_fix"], indirect=["session_fix", "module_fix"]
)
== "module"
)

def test_parametrize_and_id(self):
def func(x, y):
pass
Expand Down Expand Up @@ -1383,6 +1429,39 @@ def test_2(animal, echo):
result = testdir.runpytest()
result.stdout.fnmatch_lines(["* 3 passed *"])

def test_parametrize_some_arguments_auto_scope(self, testdir, monkeypatch):
"""Integration test for (#3941)"""
class_fix_setup = []
monkeypatch.setattr(sys, "class_fix_setup", class_fix_setup, raising=False)
func_fix_setup = []
monkeypatch.setattr(sys, "func_fix_setup", func_fix_setup, raising=False)

testdir.makepyfile(
"""
import pytest
import sys
@pytest.fixture(scope='class', autouse=True)
def class_fix(request):
sys.class_fix_setup.append(request.param)
@pytest.fixture(autouse=True)
def func_fix():
sys.func_fix_setup.append(True)
@pytest.mark.parametrize('class_fix', [10, 20], indirect=True)
class Test:
def test_foo(self):
pass
def test_bar(self):
pass
"""
)
result = testdir.runpytest_inprocess()
result.stdout.fnmatch_lines(["* 4 passed in *"])
assert func_fix_setup == [True] * 4
assert class_fix_setup == [10, 20]

def test_parametrize_issue634(self, testdir):
testdir.makepyfile(
"""
Expand Down

0 comments on commit b1e5bde

Please sign in to comment.