Skip to content

Commit 0bbddff

Browse files
committed
Add ability to automatically collect *.feature files
1 parent f3b92bd commit 0bbddff

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed

pytest_bdd/bdd_module.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import sys
2+
3+
try:
4+
from types import ModuleType
5+
except ImportError:
6+
ModuleType = type(sys)
7+
8+
from _pytest.python import Module
9+
from .scenario import scenarios
10+
11+
12+
class PytestBDDModule(Module):
13+
"""
14+
Class that represents *.feature file as python module
15+
"""
16+
17+
def _getobj(self):
18+
# Add _test suffix to module name
19+
module_name = self.nodeid.replace("/", ".").rsplit(".", 1)[0] + "_test"
20+
21+
# Create dummy module to store tests
22+
module = ModuleType(
23+
name=module_name, doc="Autogenerated python module for {!r} feature file".format(str(self.fspath))
24+
)
25+
sys.modules[module_name] = module
26+
27+
# Add scenarios for dummy module
28+
scenarios(self.fspath.basename, features_base_dir=self.fspath.dirname, module=module)
29+
30+
return module

pytest_bdd/plugin.py

+10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from . import generation
88
from . import reporting
99
from . import gherkin_terminal_reporter
10+
from .bdd_module import PytestBDDModule
1011
from .utils import CONFIG_STACK
1112

1213

@@ -36,6 +37,7 @@ def pytest_addoption(parser):
3637
def add_bdd_ini(parser):
3738
parser.addini("bdd_features_base_dir", "Base features directory.")
3839
parser.addini("bdd_strict_gherkin", "Parse features to be strict gherkin.", type="bool", default=True)
40+
parser.addini("bdd_auto_collect", "To automatically collect feature files.", type="bool", default=False)
3941

4042

4143
@pytest.mark.trylast
@@ -106,3 +108,11 @@ def item_key(item):
106108
return (item.reportinfo()[:2], declaration_order)
107109

108110
items.sort(key=item_key)
111+
112+
113+
def pytest_collect_file(path, parent):
114+
"""
115+
Automatically collect *.feature files and create test modules for them.
116+
"""
117+
if CONFIG_STACK[-1].getini("bdd_auto_collect") and path.ext == ".feature":
118+
return PytestBDDModule(parent, fspath=path)

pytest_bdd/scenario.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,11 @@ def scenarios(*feature_paths, **kwargs):
322322
323323
:param *feature_paths: feature file paths to use for scenarios
324324
"""
325-
frame = inspect.stack()[1]
326-
module = inspect.getmodule(frame[0])
325+
if "module" in kwargs:
326+
module = kwargs.pop("module")
327+
else:
328+
frame = inspect.stack()[1]
329+
module = inspect.getmodule(frame[0])
327330

328331
features_base_dir = kwargs.get("features_base_dir")
329332
if features_base_dir is None:

tests/feature/test_auto_collect.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""Auto collect tests."""
2+
import pytest
3+
4+
import textwrap
5+
6+
7+
@pytest.fixture
8+
def auto_collect_test_dir(testdir):
9+
dirname = "test_auto_collect"
10+
tests = testdir.mkpydir(dirname)
11+
12+
tests.join("foo.feature").write(
13+
textwrap.dedent(
14+
r"""
15+
Feature: The feature
16+
Scenario: Some scenario
17+
"""
18+
)
19+
)
20+
21+
22+
def test_auto_collect_tests(auto_collect_test_dir, testdir):
23+
testdir.makeini(
24+
"""
25+
[pytest]
26+
bdd_auto_collect=true
27+
"""
28+
)
29+
30+
result = testdir.runpytest()
31+
32+
result.stdout.fnmatch_lines("collected 1 item")
33+
result.assert_outcomes(passed=1)
34+
35+
36+
def test_auto_collect_tests_disabled(auto_collect_test_dir, testdir):
37+
result = testdir.runpytest()
38+
39+
result.stdout.fnmatch_lines("collected 0 items")

0 commit comments

Comments
 (0)