简体   繁体   English

如何让 py.test 或 nose 在所有 python 文件中寻找测试?

[英]How to make py.test or nose to look for tests inside all python files?

I do have several small modules 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.我确实有几个小模块,其中测试在其中, py.testnose不查找它们,因为它们的文件名中不包含test

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'''?我如何说服py.testnose递归地在所有 python 文件中查找测试 - '''包括文件名中没有test的文件'''?

Inside the source files I do keep the standard naming convention: class testSomeName with methods def test_some_name .在源文件中,我确实保留了标准命名约定: class testSomeName和方法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.我不想手动创建包含测试的所有文件的列表,我想要一个支持发现的解决方案。

With py.test it's simple. 使用py.test它很简单。 Create a conftest.py file with this content: 使用此内容创建conftest.py文件:

# 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. 这将扩展收集过程,为每个“.py”文件创建一个测试“模块”节点。 Putting this into a conftest.py file makes it a project-specific extension which is automatically loaded if you type: 将它放入conftest.py文件使其成为特定于项目的扩展,如果您键入以下内容,则会自动加载:

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. 如果需要,您还可以将上述conftest.py文件打包为可安装的插件,并通过安装插件使扩展可用。 In this case you do not need any conftest.py file at all. 在这种情况下,您根本不需要任何conftest.py文件。

Put a file "setup.cfg" at the root of project, and it contains this two lines: 在项目的根目录下放置一个“setup.cfg”文件,它包含以下两行:

[pytest]
python_files=*.py

then py.test select tests from all *.py files. 然后py.test从所有*.py文件中选择测试。 Here it's explained: pytest docs 在这里解释: 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. 您还可以查看Nose ,它将发现测试而无需使用固定的文件名约定。

You can bypass the regexp used to filter files in nose with the following code. 您可以使用以下代码绕过用于过滤nose中文件的正则表达式。 Create a python module (ie my_nosetests.py ) 创建一个python模块(即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. 现在运行my_nosetests.py就像运行nosetests ,你应该运行你的测试。 Be aware that you are in fact loading all modules and searching for tests in them. 请注意,您实际上正在加载所有模块并在其中搜索测试。 Beware of any side effect of module loading. 注意模块加载的任何副作用。

The documentation says that 文档说明了这一点

By default all directories not starting with a dot are traversed, looking for test_*.py and *_test.py files. 默认情况下,遍历所有不以点开头的目录,查找test _ *。py和* _test.py文件。 Those Python files are imported under their package name. 这些Python文件是在其包名下导入的。

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? (Caveat Emptor:我没有尝试/测试过这个)如何使用提供的钩子来收集目录和文件?

py.test calls the following two fundamental hooks for collecting files and directories: py.test调用以下两个用于收集文件和目录的基本钩子:

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 the parent.config object. parent对象是父节点,可用于通过parent.config对象访问命令行选项。

For pytest-6 I had to change @hpk42 answer to directly return a Module instance for the given source/test code layout.对于 pytest-6,我必须更改 @hpk42 答案以直接返回给定源/测试代码布局的 Module 实例。 The original answer raised an exception for this major version of pytest, as the API has changed in the meantime.原始答案针对 pytest 这个主要版本提出了一个例外,因为 API 同时发生了变化。

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM