added support for glob-style patterns to python_classes and python_functions config options

fixes #600

--HG--
branch : python-classes-glob
This commit is contained in:
Bruno Oliveira 2014-10-16 19:27:10 -03:00
parent 4337e9c4ba
commit b928928942
4 changed files with 73 additions and 23 deletions

View File

@ -1,4 +1,5 @@
""" Python test discovery, setup and run of test functions. """
import fnmatch
import py
import inspect
import sys
@ -127,9 +128,10 @@ def pytest_addoption(parser):
default=['test_*.py', '*_test.py'],
help="glob-style file patterns for Python test module discovery")
parser.addini("python_classes", type="args", default=["Test",],
help="prefixes for Python test class discovery")
help="prefixes or glob names for Python test class discovery")
parser.addini("python_functions", type="args", default=["test",],
help="prefixes for Python test function and method discovery")
help="prefixes or glob names for Python test function and "
"method discovery")
def pytest_cmdline_main(config):
if config.option.showfixtures:
@ -307,14 +309,22 @@ class PyobjMixin(PyobjContext):
class PyCollector(PyobjMixin, pytest.Collector):
def funcnamefilter(self, name):
for prefix in self.config.getini("python_functions"):
if name.startswith(prefix):
return True
return self._matches_prefix_or_glob_option('python_functions', name)
def classnamefilter(self, name):
for prefix in self.config.getini("python_classes"):
if name.startswith(prefix):
return self._matches_prefix_or_glob_option('python_classes', name)
def _matches_prefix_or_glob_option(self, option_name, name):
"""
checks if the given name matches the prefix or glob-pattern defined
in ini configuration.
"""
for option in self.config.getini(option_name):
if name.startswith(option):
return True
elif fnmatch.fnmatch(name, option):
return True
return False
def collect(self):
if not getattr(self.obj, "__test__", True):

View File

@ -115,17 +115,33 @@ Builtin configuration file options
.. confval:: python_classes
One or more name prefixes determining which test classes
are considered as test modules.
One or more name prefixes or glob-style patterns determining which classes
are considered for test collection. Here is an example of how to collect
tests from classes that end in ``Suite``::
# content of pytest.ini
[pytest]
python_classes = *Suite
Note that ``unittest.TestCase`` derived classes are always collected
regardless of this option, as ``unittest``'s own collection framework is used
to collect those tests.
.. confval:: python_functions
One or more name prefixes determining which test functions
and methods are considered as test modules. Note that this
has no effect on methods that live on a ``unittest.TestCase``
derived class.
One or more name prefixes or glob-patterns determining which test functions
and methods are considered tests. Here is an example of how
to collect test functions and methods that end in ``_test``::
See :ref:`change naming conventions` for examples.
# content of pytest.ini
[pytest]
python_functions = *_test
Note that this has no effect on methods that live on a ``unittest
.TestCase`` derived class, as ``unittest``'s own collection framework is used
to collect those tests.
See :ref:`change naming conventions` for more detailed examples.
.. confval:: doctest_optionflags

View File

@ -26,17 +26,17 @@ the :confval:`python_files`, :confval:`python_classes` and
[pytest]
python_files=check_*.py
python_classes=Check
python_functions=check
python_functions=*_check
This would make ``pytest`` look for ``check_`` prefixes in
Python filenames, ``Check`` prefixes in classes and ``check`` prefixes
in functions and classes. For example, if we have::
This would make ``pytest`` look for tests in files that match the ``check_*
.py`` glob-pattern, ``Check`` prefixes in classes, and functions and methods
that match ``*_check``. For example, if we have::
# content of check_myapp.py
class CheckMyApp:
def check_simple(self):
def simple_check(self):
pass
def check_complex(self):
def complex_check(self):
pass
then the test collection looks like this::
@ -48,14 +48,14 @@ then the test collection looks like this::
<Module 'check_myapp.py'>
<Class 'CheckMyApp'>
<Instance '()'>
<Function 'check_simple'>
<Function 'check_complex'>
<Function 'simple_check'>
<Function 'complex_check'>
============================= in 0.01 seconds =============================
.. note::
the ``python_functions`` and ``python_classes`` has no effect
the ``python_functions`` and ``python_classes`` options has no effect
for ``unittest.TestCase`` test discovery because pytest delegates
detection of test case methods to unittest code.

View File

@ -528,6 +528,30 @@ class Test_genitems:
assert s.endswith("test_example_items1.testone")
print(s)
def test_class_and_functions_discovery_using_glob(self, testdir):
"""
tests that python_classes and python_functions config options work
as prefixes and glob-like patterns (issue #600).
"""
testdir.makeini("""
[pytest]
python_classes = *Suite Test
python_functions = *_test test
""")
p = testdir.makepyfile('''
class MyTestSuite:
def x_test(self):
pass
class TestCase:
def test_y(self):
pass
''')
items, reprec = testdir.inline_genitems(p)
ids = [x.getmodpath() for x in items]
assert ids == ['MyTestSuite.x_test', 'TestCase.test_y']
def test_matchnodes_two_collections_same_file(testdir):
testdir.makeconftest("""
import pytest