4

我正在编写一个插件,它将以不同的方式分别对待我的单元测试、功能测试和集成测试。
我的测试文件夹将具有以下结构:

/tests
-- /unit
-- /functional
-- /integration

每个单元测试将驻留在单元目录中,每个功能测试将驻留在功能目录中,依此类推。

我熟悉Layers插件,但我宁愿让我的测试遵循约定。
在运行测试之前,我应该使用哪个钩子来注入适当的层?应该是loadTestsFromModule钩子吗?你能给我举个例子吗?

我还想将每种测试的摘要报告分开。
我应该使用哪个钩子?

4

3 回答 3

2

我通过使用nose2attrib插件进行发现和从nose1attrib插件复制的一些代码来使用nose2,这使我可以装饰我的测试。

使用nose2attrib插件

您将看到nose2attrib插件允许在测试函数和类上定义自定义属性。

为此,您必须在定义测试函数后指定测试的属性。

class MyTestCase(unittest.TestCase):
    def test_function(self):
        self.assertEqual(1+1, 2)
    test_function.custom_attr1 = True
    test_function.custom_attr2 = ['foo', 'bar']

-A然后,您可以通过指定或--attribute作为命令行参数来运行一组过滤测试,nose2以列出您要与测试套件匹配的属性。您甚至可以使用 or 的表达式命令行参数,它允许更复杂的 Python 表达式来匹配测试属性。-E--eval-attribute

例如nose2 -v -A custom_attr1
,将运行所有具有custom_attr1指定值的测试。

使用装饰器指定测试属性

但这对我来说还不够好,因为我不喜欢在定义后在测试中定义这些属性的想法。我想改用装饰器,但nose2没有内置的装饰器来做这件事。

我去了nose1attrib插件的源代码并复制了attr函数的源代码。

def attr(*args, **kwargs):
    """Decorator that adds attributes to classes or functions
    for use with the Attribute (-a) plugin.
    """
    def wrap_ob(ob):
        for name in args:
            setattr(ob, name, True)
        for name, value in kwargs.iteritems():
            setattr(ob, name, value)
        return ob
    return wrap_ob

我把它放到一个test/attrib_util.py文件中。现在我可以使用装饰器指定属性。我上面的原始测试类代码可以转换为更简单的(IMO):

from test.attrib_util import attr

class MyTestCase(unittest.TestCase):
    @attr('custom_attr1', custom_attr2=['foo', 'bar'])
    def test_function(self):
        self.assertEqual(1+1, 2)

您会注意到属性可以指定为 args 或 kwargs;所有 args 将获得默认值True.

您甚至可以attr在测试类或基类上使用此装饰器,这些属性将应用于其中定义的所有测试函数。这允许非常容易地分离单元测试和功能测试。

from test.attrib_util import attr

@attr('functional')
class FunctionalTestCase(unittest.TestCase):
    pass

class MyFunctionalCase(FunctionalTestCase):
    def test_function(self):
        print 'this will be considered a "functional" test function'
于 2016-02-16T16:35:03.403 回答
1

您无需编写插件,内置的 attr 模块就是为此目的而设计的。但是,它不依赖于您的文件层次结构。相反,您将单个测试标记为单元、功能或集成。这看起来像:

from nose.plugins import attrib

@attrib.attr("functional")
class FunctionalTestCase(unittest.TestCase):
    pass

要仅运行功能测试,您将执行以下操作:

nosetests -a functional

如果我正在创建这个测试布局,我可能会有 3 个 unittest.TestCase 子类,已经用“unit”、“functional”和“integration”标记。新测试可以轻松继承正确的测试类型。

于 2013-10-21T19:30:31.070 回答
0

如果您已经将测试分类到目录中(如您所述),您可以编写一个使用wantDirectory方法的插件。

import os.path
from nose.plugins import Plugin

class TestCategory(Plugin):
    """
    Run tests in a defined category (unittest, functional, integration.  Always
    runs uncategorized tests.
    """
    def wantDirectory(self, dirname):
         dirname = os.path.basename(dirname)
         if (dirname in ('unit', 'functional', 'integration') and 
             dirname != self.category):
             return False
         return None

您将需要为此插件编写方法来处理启用和禁用它以及收集用户对类别的选择options()configure()运行鼻子测试时,您可以从以下三个类别中进行选择:

nosetests --category functional

由于一次只运行一个测试类别,您将获得每个测试类别的单独报告。当然,您始终可以通过不启用此插件来运行所有测试。

(添加为不同的答案,因为它是一种完全不同的方法)。

于 2013-10-21T19:51:09.000 回答