How to make py.test or nose to look for tests inside all python files?
I do have several small mo开发者_如何学Godules where the tests are inside them and py.test
or nose
does not look for them because they do not contain test
in their filename.
How can I convince py.test
or nose
to look for tests inside all python files, recursively - '''including the ones that do not have test
in their filenames'''?
Inside the source files I do keep the standard naming convention: class testSomeName
with methods def test_some_name
.
If this is not possible, what other solution can I use to obtain the same result.
I do not want to manually create a list of all files containing the test, I want a solution that supports discovery.
Put a file "setup.cfg" at the root of project, and it contains this two lines:
[pytest]
python_files=*.py
then py.test select tests from all *.py
files. Here it's explained: pytest docs
with Nose:
nosetests --all-modules
You can also have a look at Nose which will discover tests without having to use a fixed file name convention.
You can bypass the regexp used to filter files in nose with the following code.
Create a python module (i.e. my_nosetests.py
)
import nose
from nose.plugins.base import Plugin
class ExtensionPlugin(Plugin):
name = "ExtensionPlugin"
def options(self, parser, env):
Plugin.options(self,parser,env)
def configure(self, options, config):
Plugin.configure(self, options, config)
self.enabled = True
def wantFile(self, file):
return file.endswith('.py')
def wantDirectory(self,directory):
return True
def wantModule(self,file):
return True
if __name__ == '__main__':
includeDirs = ["-w", ".", ".."]
nose.main(addplugins=[ExtensionPlugin()], argv=sys.argv.extend(includeDirs))
Now run my_nosetests.py
as if you were running nosetests
and you should have your tests running. Be aware that you are in fact loading all modules and searching for tests in them. Beware of any side effect of module loading.
With py.test it's simple. Create a conftest.py
file with this content:
# content of conftest.py file at root of your project
def pytest_collect_file(path, parent):
if path.ext == ".py":
return parent.Module(path, parent)
This will extend the collection process to create a test "Module" node for each ".py" file. Putting this into a conftest.py
file makes it a project-specific extension which is automatically loaded if you type:
py.test
For informational purposes you can also type:
py.test --collectonly
to see what tests and files are collected, example output:
<Directory 'morecollect'>
<Module 'conftest.py'>
<Directory 'pkg'>
<Module 'test_x.py'>
<Function 'test_hello2'>
<Module 'x.py'> # this is collected because of our conftest.py extension
<Function 'test_hello'>
If needed you can also package the above conftest.py
file as an installable plugin and make the extension available by installing the plugin. In this case you do not need any conftest.py
file at all.
The documentation says that
By default all directories not starting with a dot are traversed, looking for test_*.py and *_test.py files. Those Python files are imported under their package name.
Can you ensure that this is the case with your code?
Update
(Caveat Emptor: I haven't tried/tested this) How about using the hooks provided for collecting directories and files?
py.test calls the following two fundamental hooks for collecting files and directories:
def pytest_collect_directory(path, parent):
""" return Collection node or None for the given path. """
def pytest_collect_file(path, parent):
""" return Collection node or None for the given path. """
Both return a collection node for a given path. All returned nodes from all hook implementations will participate in the collection and running protocol. The
parent
object is the parent node and may be used to access command line options via theparent.config
object.
For pytest-6 I had to change @hpk42 answer to directly return a Module instance for the given source/test code layout. The original answer raised an exception for this major version of pytest, as the API has changed in the meantime.
def pytest_collect_file(path, parent):
"""Look in all Python files for test cases."""
from _pytest.python import Module
if path.ext == ".py":
return Module.from_parent(parent, fspath=path)
精彩评论