如何编写一个分隔不同类型测试的nose2插件?

时间:2013-05-30 01:12:53

标签: python testing nose2

我正在编写一个插件,将单独处理我的单元测试,功能测试和整合测试不同。
我的tests文件夹将具有以下结构:

  

/测试
    - / unit
    - /功能
    - / integration

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

我熟悉Layers插件,但我宁愿按照惯例进行测试 在测试运行之前,我应该使用哪个钩子来注入适当的层? 它应该是loadTestsFromModule钩子吗?你能告诉我一个例子吗?

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

3 个答案:

答案 0 :(得分:1)

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

from nose.plugins import attrib

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

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

nosetests -a functional

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

答案 1 :(得分:1)

我通过使用nose2 attrib插件进行发现以及从nose1 attrib插件复制的一些代码使我能够装饰我的测试,从而使用了nose2。

使用nose2 attrib插件

您将看到the nose2 attrib plugin允许在测试函数和类上定义自定义属性。

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

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命令行参数来运行一组筛选的测试,以列出要与测试套件匹配的属性。您甚至可以使用-E--eval-attribute expression command-line argument,它允许更复杂的Python表达式来匹配测试属性。

e.g。 nose2 -v -A custom_attr1
将运行所有使用 truthy 值指定custom_attr1的测试。

使用装饰器指定测试属性

这对我来说还不够好,因为我不喜欢在定义后在测试中定义这些属性的想法。我想使用装饰器,但nose2没有内置装饰器来执行此操作。

我转到了nose1 source code for its attrib plugin并复制了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;所有参数都将获得默认值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'

答案 2 :(得分: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时,您可以从以下三个类别中进行选择:

nosetests --category functional

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

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