Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在nose或pytest中收集编程生成的测试套件的好方法_Python_Nose_Pytest - Fatal编程技术网

Python 在nose或pytest中收集编程生成的测试套件的好方法

Python 在nose或pytest中收集编程生成的测试套件的好方法,python,nose,pytest,Python,Nose,Pytest,假设我有一个这样的测试套件: class SafeTests(unittest.TestCase): # snip 20 test functions class BombTests(unittest.TestCase): # snip 10 different test cases 我目前正在做以下工作: suite = unittest.TestSuite() loader = unittest.TestLoader() safetests = loader.loadTe

假设我有一个这样的测试套件:

class SafeTests(unittest.TestCase):
    # snip 20 test functions

class BombTests(unittest.TestCase):
    # snip 10 different test cases
我目前正在做以下工作:

suite = unittest.TestSuite()
loader = unittest.TestLoader()
safetests = loader.loadTestsFromTestCase(SafeTests)
suite.addTests(safetests)

if TARGET != 'prod':
    unsafetests = loader.loadTestsFromTestCase(BombTests)
    suite.addTests(unsafetests)


unittest.TextTestRunner().run(suite)
我有一个大问题,还有一个有趣的问题

  • 我想使用nose或py.test(哪种都不重要)
  • 我有大量不同的应用程序公开这些测试 通过入口的套房

    我希望能够在所有已安装的系统中聚合这些自定义测试 所以我不能仅仅使用一个聪明的命名约定。我不 特别关心这些通过入口点暴露,但我 是否关心是否能够在中跨应用程序运行测试 网站包。(不只是导入…每个模块。)

我不在乎维持目前对它的依赖
unittest.TestCase
,破坏这种依赖性实际上是一个目标


编辑这是为了确认@Oleksiy关于将参数传递给
nose.run
确实有一些警告

不起作用的事情:

  • 传递想要执行的所有文件(这很奇怪)
  • 传递要执行的所有模块。(这两种方法都可以执行 没有,错误的事情,或者太多的事情。有趣的例子是0,1或 很多,也许吧?)
  • 在目录之前传入模块:目录必须到达 首先,否则您将得到重复的测试
这种脆弱性是荒谬的,如果你有改进它的想法,我欢迎 评论,或者我设置

除此之外,还有以下工作,包括挑选多个项目 安装到站点包中:

#!python
import importlib, os, sys
import nose

def runtests():
    modnames = []
    dirs = set()
    for modname in sys.argv[1:]:
        modnames.append(modname)

        mod = importlib.import_module(modname)
        fname = mod.__file__
        dirs.add(os.path.dirname(fname))

    modnames = list(dirs) + modnames

    nose.run(argv=modnames)

if __name__ == '__main__':
    runtests()
如果将其保存到
runtests.py
文件中,则在以以下方式运行时会执行正确的操作:

runtests.py project.tests otherproject.tests
如果您的问题是“如何让pytest‘查看’测试?”,则需要在每个测试文件和每个测试用例(即函数)前面加上“test”。然后,只需在pytest命令行上传递要搜索的目录,它将递归搜索与“test_XXX.py”匹配的文件,从这些文件中收集“test_XXX”函数并运行它们

至于文档,您可以尝试启动


如果您不喜欢默认的pytest测试收集方法,您可以使用nose的方向对其进行自定义。您可以将两个测试都设置到位,并使用插件选择要运行的测试,这对于选择要运行的测试非常有用。我将保留这两个测试并为它们分配属性:

from nose.plugins.attrib import attr

@attr("safe")
class SafeTests(unittest.TestCase):
    # snip 20 test functions

class BombTests(unittest.TestCase):
    # snip 10 different test cases
对于生产代码,我只需使用
nosetests-a safe
调用nose,或者在操作系统生产测试环境中设置
nose\u ATTR=safe
,或者在nose对象上调用run方法,以基于
目标的
-a
命令行选项在python中本机运行它:

import sys
import nose

if __name__ == '__main__':
    module_name = sys.modules[__name__].__file__
    argv = [sys.argv[0], module_name]
    if TARGET == 'prod':
        argv.append('-a slow')

    result = nose.run(argv=argv)

最后,如果由于某种原因您的测试没有被发现,您可以使用
@istest
属性(
来自nose.tools import istest
)将它们显式标记为测试。

结果是一团糟:nose几乎完全使用
TestLoader.load\u tests\u from\u names
函数(这是在中测试的唯一函数 ) 因此,由于我想从任意python对象实际加载内容,我 似乎需要我自己写出来,弄清楚使用哪种加载函数

然后,另外,要正确地让事情像
nosetests
脚本那样工作 我需要进口大量的东西。我一点也不确定这个 是做事情的最好方式,甚至不是那种。但这是一个精简版 对我有用的示例(无错误检查,不太详细):

import sys
import types
import unittest

from nose.config import Config, all_config_files
from nose.core import run
from nose.loader import TestLoader
from nose.suite import ContextSuite
from nose.plugins.manager import PluginManager

from myapp import find_test_objects

def load_tests(config, obj):
    """Load tests from an object

    Requires an already configured nose.config.Config object.

    Returns a nose.suite.ContextSuite so that nose can actually give
    formatted output.
    """

    loader = TestLoader()
    kinds = [
        (unittest.TestCase, loader.loadTestsFromTestCase),
        (types.ModuleType, loader.loadTestsFromModule),
        (object, loader.loadTestsFromTestClass),
    ]
    tests = None
    for kind, load in kinds.items():
        if isinstance(obj, kind) or issubclass(obj, kind):
            log.debug("found tests for %s as %s", obj, kind)
            tests = load(obj)
            break

    suite = ContextSuite(tests=tests, context=obj, config=config)

def main():
    "Actually configure the nose config object and run the tests"
    config = Config(files=all_config_files(), plugins=PluginManager())
    config.configure(argv=sys.argv)

    tests = []
    for group in find_test_objects():
        tests.append(load_tests(config, group))

    run(suite=tests)

如果您愿意更改代码以生成
py.test
“套件”(我的定义)而不是unittest套件(技术术语),您可以很容易地做到这一点。创建一个名为
conftest.py
的文件,如下所示

import pytest

def pytest_collect_file(parent, path):
    if path.basename == "foo":
        return MyFile(path, parent)

class MyFile(pytest.File):
    def collect(self):
        myname="foo"
        yield MyItem(myname, self)
        yield MyItem(myname, self)

class MyItem(pytest.Item):
    SUCCEEDED=False
    def __init__(self, name, parent):
        super(MyItem, self).__init__(name, parent)

    def runtest(self):
        if not MyItem.SUCCEEDED:
            MyItem.SUCCEEDED = True
            print "good job, buddy"
            return
        else:
            print "you sucker, buddy"
            raise Exception()

    def repr_failure(self, excinfo):
        return ""
您将在其中生成代码/将代码添加到
MyFile
MyItem
类中(与
unittest.TestSuite
unittest.TestCase
相反)。我以这种方式保留了
MyFile
类的命名约定,因为它旨在表示您从文件中读取的内容,但当然您基本上可以将其解耦(正如我在这里所做的)。有关这方面的官方示例,请参见。唯一的限制是,我编写的
foo
必须作为文件存在,但您也可以将其解耦,例如使用
conftest.py
或树中存在的任何其他文件名(并且只运行一次,否则所有匹配的文件都将运行—如果您不对树中存在的每个文件执行
if path.basename
测试!!!)

您可以使用从命令行运行此命令

py.test -whatever -options
或者从你使用的任何代码中编程

import pytest
pytest.main("-whatever -options")

py.test的好处在于,您可以解锁许多非常强大的插件,例如

不,我知道如何使用py.test,并且我的测试有正确的名称,我希望能够告诉pytest“这个由脚本生成的测试集合”。(我正在动态生成测试套件,因此命名基于标准名称的测试发现不起作用。)@quodlibetor:所以当你说你在“动态生成测试套件”时,你并不是在将它们写入文件(a la'a.example.com/test/test_XXX.py')但是它们是作为Python对象生成的吗?谢谢,
@attr
标志非常好,解决了我问题中精心设计的部分,但我不知道如何将我的所有attr公开给外部应用程序?你不能从外部应用程序设置环境变量吗?我猜你说的是显式地传递所有mod运行
nose.run
?除非nose知道如何自动加载测试套件,否则我认为这是行不通的。fwiw我试过了,并做了
nose.run($VIRTALENV\u SITE\u PACKAGES/package/tests.py)
(请原谅伪pybash),除非从
$VIRTUAL中运行它,否则它是行不通的