禁用Python nosetests

53

在使用 Python 的 nosetests 进行单元测试时,可以通过将测试函数的 __test__ 属性设置为 false 来禁用单元测试。我使用以下装饰器实现了这一功能:

def unit_test_disabled():
    def wrapper(func):
         func.__test__ = False
         return func

    return wrapper

@unit_test_disabled
def test_my_sample_test()
    #code here ...

然而,这样做会有一个副作用,即将包装器函数作为单元测试运行。虽然包装器函数总是会通过测试,但它也会出现在nosetests的输出中。是否有另一种方法来构建装饰器,使得测试不会运行且不会出现在nosetests的输出中。

5个回答

156

1
测试将不会被执行,也不会被标记为跳过...有时候抛出SkipTest异常会更有用,正如@Anders Waldenborg的回答所建议的那样,这样就能在结果中看到一些测试被跳过了。 - Serge
这是优雅的,因为一个人可以从@nottest类继承,并仍然可以将后代标记为@istest。我相信我已经到处寻找如何实现这种行为,而这是唯一一个在不拆开代码的情况下工作的方法。(嵌套后代类以避免鼻子的跟踪器使整个事情看起来很糟糕 :/) - Rubens

75
你也可以使用 unittest.skip 装饰器:
import unittest


@unittest.skip("temporarily disabled")
class MyTestCase(unittest.TestCase):
    ...

1
也可以与nose一起完美地工作,还适用于函数。太棒了!请参见http://pybites.blogspot.fr/2009/03/unittest-now-with-test-skipping-finally.html - gaborous
1
只要您将@unittest.skip()放在其他装饰器下面,即使使用node_parameterized中的@parameterized.expand()装饰器进行参数化测试,也可以很好地运行。 - CivFan
我通常使用@unittest.skipIf(True, 'SkippingTests message'),它提供了一些灵活性,使得有条件地跳过测试成为可能。 - NotTooTechy

32

在nosetest中也有一个skiptest插件,它将导致测试在测试输出中显示为跳过。这是一个用于实现该功能的装饰器:

def skipped(func):
    from nose.plugins.skip import SkipTest
    def _():
        raise SkipTest("Test %s is skipped" % func.__name__)
    _.__name__ = func.__name__
    return _

示例输出:

$ nosetests tests
..........................................................................
..................................S.............
----------------------------------------------------------------------
Ran 122 tests in 2.160s

OK (SKIP=1)

5
在测试开始时,您可以只需编写raise SkipTest。此外,请注意您还可以导入from nose import SkipTest - ire_and_curses
请注意文档说明:通常情况下,您可以使用TestCase.skipTest()或跳过修饰符之一来代替直接引发此异常。 - Zitrax
raise SkipTest,是动态决定测试运行或跳过的好方法。不足之处是,如果您正在使用Jenkins,则需要编写junit.xml,并使用通用标签进行编写。 - NotTooTechy

10
如果你以下划线开头命名类、方法或函数,nose会忽略它。 @nottest 有它的用处,但我发现当类彼此派生时,有些基类必须被nose忽略时,它并不起作用。这在我需要测试一系列相似Django视图时经常发生。它们通常共享需要测试的特征。例如,它们只能由具有某些权限的用户访问。我将这样的共享测试放在一个初始类中,其他类从该类派生。然而问题在于,基类仅供后面的类派生使用,不适合自己运行。以下是问题示例:
from unittest import TestCase

class Base(TestCase):

    def test_something(self):
        print "Testing something in " + self.__class__.__name__

class Derived(Base):

    def test_something_else(self):
        print "Testing something else in " + self.__class__.__name__

并且运行nose的输出为:

$ nosetests test.py -s
Testing something in Base
.Testing something in Derived
.Testing something else in Derived
.
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

测试中包括 Base 类。

我不能只是在 Base 上随便加上 @nottest,因为它会标记整个继承体系。实际上,如果你只在上面的代码中添加 @nottestclass Base 前面,那么 nose 将不会运行任何测试。

我所做的是在基类前面添加下划线:

from unittest import TestCase

class _Base(TestCase):

    def test_something(self):
        print "Testing something in " + self.__class__.__name__

class Derived(_Base):

    def test_something_else(self):
        print "Testing something else in " + self.__class__.__name__

当运行它时,_Base 将被忽略:

$ nosetests test3.py -s
Testing something in Derived
.Testing something else in Derived
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

这种行为并没有很好的文档说明,但是选择测试的代码明确检查了类名开始处是否有下划线

Nose也会对函数和方法名执行类似的测试,因此可以通过在名称开头添加下划线来排除它们。


-18

我认为您还需要将装饰器重命名为没有测试的名称。对于我来说,以下内容仅在第二个测试失败,而第一个测试未显示在测试套件中。

def unit_disabled(func):
    def wrapper(func):
         func.__test__ = False
         return func

    return wrapper

@unit_disabled
def test_my_sample_test():
    assert 1 <> 1

def test2_my_sample_test():
    assert 1 <> 1

9
为什么不删除这篇帖子并获得你的“同侪压力”徽章? - Chris Huang-Leaver
1
为什么这个被踩得这么惨?原因不明确。 - CaffeineConnoisseur
10
下投票的理由基于两个方面的结合:(1)答案应该是这样的:“当你阅读文档(或源代码)后发现已经有相对应的装饰器可用时,不要自己实现一个”,(2)尽管如此,这个答案还被采纳了。如果这个答案只是简单地避免在装饰器名称中使用“test”,那么它本可以很有帮助。 - Martin Thorsen Ranang
这是一个糟糕的重新发明轮子。 - meawoppl
我认为一旦有人对答案进行了评论和投票,就无法删除答案。 - Veltzer Doron
也许StackOverflow需要一种更好的方式来列出两个有效的解决方案,并根据点赞数对它们进行排序。一个问题一个解决方案的模式在软件开发的许多方面都不是理想的。这就像把软件开发当作数学一样,但实际上并不是这样的。 - user7440787

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接