Skip to content

Commit 222457d

Browse files
committed
Add discover_imports in conf
- Allows a user to define whether or not pytest should treat imported (but not in testpaths) as test classes. - Imagine a class is called TestFoo defined in src/ dir, when discover_imports is disabled, TestFoo is not treated as a test class.
1 parent 9515dfa commit 222457d

File tree

5 files changed

+103
-0
lines changed

5 files changed

+103
-0
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ Stefanie Molin
400400
Stefano Taschini
401401
Steffen Allner
402402
Stephan Obermann
403+
Sven
403404
Sven-Hendrik Haase
404405
Sviatoslav Sydorenko
405406
Sylvain Marié

changelog/12749.feature.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add :confval:`discover_imports`, when disabled (default) will make sure to not consider classes which are imported by a test file and starts with Test.
2+
3+
-- by :user:`FreerGit`

src/_pytest/main.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ def pytest_addoption(parser: Parser) -> None:
7878
type="args",
7979
default=[],
8080
)
81+
parser.addini(
82+
"discover_imports",
83+
"Whether to discover tests in imported modules outside `testpaths`",
84+
default=False,
85+
)
8186
group = parser.getgroup("general", "Running and selection options")
8287
group._addoption(
8388
"-x",

src/_pytest/python.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,12 @@ def newinstance(self):
741741
return self.obj()
742742

743743
def collect(self) -> Iterable[nodes.Item | nodes.Collector]:
744+
if self.config.getini("discover_imports") == ("false" or False):
745+
paths = self.config.getini("testpaths")
746+
class_file = inspect.getfile(self.obj)
747+
if not any(string in class_file for string in paths):
748+
return []
749+
744750
if not safe_getattr(self.obj, "__test__", True):
745751
return []
746752
if hasinit(self.obj):

testing/test_discover_imports.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import pytest
2+
import textwrap
3+
4+
def test_discover_imports_enabled(pytester):
5+
src_dir = pytester.mkdir("src")
6+
tests_dir = pytester.mkdir("tests")
7+
pytester.makeini("""
8+
[pytest]
9+
testpaths = "tests"
10+
discover_imports = true
11+
""")
12+
13+
src_file = src_dir / "foo.py"
14+
15+
src_file.write_text(textwrap.dedent("""\
16+
class TestClass(object):
17+
def __init__(self):
18+
super().__init__()
19+
20+
def test_foobar(self):
21+
return true
22+
"""
23+
), encoding="utf-8")
24+
25+
test_file = tests_dir / "foo_test.py"
26+
test_file.write_text(textwrap.dedent("""\
27+
import sys
28+
import os
29+
30+
current_file = os.path.abspath(__file__)
31+
current_dir = os.path.dirname(current_file)
32+
parent_dir = os.path.abspath(os.path.join(current_dir, '..'))
33+
sys.path.append(parent_dir)
34+
35+
from src.foo import TestClass
36+
37+
class TestDomain:
38+
def test_testament(self):
39+
testament = TestClass()
40+
pass
41+
"""), encoding="utf-8")
42+
43+
result = pytester.runpytest()
44+
result.assert_outcomes(errors=1)
45+
46+
def test_discover_imports_disabled(pytester):
47+
48+
src_dir = pytester.mkdir("src")
49+
tests_dir = pytester.mkdir("tests")
50+
pytester.makeini("""
51+
[pytest]
52+
testpaths = "tests"
53+
discover_imports = false
54+
""")
55+
56+
src_file = src_dir / "foo.py"
57+
58+
src_file.write_text(textwrap.dedent("""\
59+
class Testament(object):
60+
def __init__(self):
61+
super().__init__()
62+
self.collections = ["stamp", "coin"]
63+
64+
def personal_property(self):
65+
return [f"my {x} collection" for x in self.collections]
66+
"""
67+
), encoding="utf-8")
68+
69+
test_file = tests_dir / "foo_test.py"
70+
test_file.write_text(textwrap.dedent("""\
71+
import sys
72+
import os
73+
74+
current_file = os.path.abspath(__file__)
75+
current_dir = os.path.dirname(current_file)
76+
parent_dir = os.path.abspath(os.path.join(current_dir, '..'))
77+
sys.path.append(parent_dir)
78+
79+
from src.foo import Testament
80+
81+
class TestDomain:
82+
def test_testament(self):
83+
testament = Testament()
84+
assert testament.personal_property()
85+
"""), encoding="utf-8")
86+
87+
result = pytester.runpytest()
88+
result.assert_outcomes(passed=1)

0 commit comments

Comments
 (0)