32

我希望我的 Python unittest模块告诉测试运行者在某些情况下完全跳过它(例如无法导入模块或定位关键资源)。

我可以@unittest.skipIf(...)用来跳过unittest.TestCase类,但是如何跳过整个模块?将跳过应用于每个类是不够的,因为如果模块无法导入,类定义本身可能会导致异常。

4

11 回答 11

22

如果查看 and 的定义unittest.skipIfunittest.skip您可以看到raise unittest.SkipTest(reason)执行测试时,关键是在做。如果您可以将它显示为一个跳过的测试而不是测试运行器中的几个,您可以简单地unittest.SkipTest在导入时提高自己:

import unittest
try:
    # do thing
except SomeException:
    raise unittest.SkipTest("Such-and-such failed. Skipping all tests in foo.py")

运行nosetests -v给出:

Failure: SkipTest (Such-and-such failed. Skipping all tests in foo.py) ... SKIP:
Such-and-such failed. Skipping all tests in foo.py

----------------------------------------------------------------------
Ran 1 test in 0.002s

OK (SKIP=1)
于 2012-09-19T04:22:04.150 回答
14

我发现在 setUp 中使用 skipTest 效果很好。如果您需要导入一个模块,您可以使用 try 块来设置例如 module_failed = True,如果已设置,则在 setUp 中调用 skipTest。这报告了正确的测试跳过次数,只需要一个简短的尝试块:

import unittest

try:
    import my_module
    module_failed = False
except ImportError:
    module_failed = True

class MyTests(unittest.TestCase):
    def setUp(self):
        if module_failed:
            self.skipTest('module not tested')

    def test_something(self):
            #...
于 2014-05-08T08:42:33.153 回答
8

在这里查看其他答案后,这是我想出的最佳答案。将整个测试套件嵌入到异常处理中很丑陋,但它似乎可以满足您的需求。当导入不起作用时,特别是跳过测试。

假设您正在谈论使用nosetests -x 来运行它应该在跳过的测试之后继续进行的测试,至少在我尝试它时它似乎如此。

import unittest
try:
    import PyQt4
    # the rest of the imports


    # actual tests go here.
    class TestDataEntryMixin(unittest.TestCase):
        def test_somefeature(self):
            # ....

except ImportError, e:
    if e.message.find('PyQt4') >= 0:
        class TestMissingDependency(unittest.TestCase):

            @unittest.skip('Missing dependency - ' + e.message)
            def test_fail():
                pass
    else:
        raise

if __name__ == '__main__':
    unittest.main()

如果导入失败,它将用一个简单地跳过的测试替换测试运行。我还试图确保它不会无意中吞下任何异常。该解决方案很大程度上归功于该问题的所有其他答案和评论。

如果你在详细模式下运行它,你会在它跳过时看到这个,

test_fail (test_openihm_gui_interface_mixins.TestMissingDependency) ... skipped 'Missing dependency - No module named PyQt4'
于 2012-09-20T10:12:54.537 回答
6
@unittest.skip('comments_for_skipping_unit_tests')
class MyTests(unittest.TestCase):
def setUp(self):
    pass

def test_something(self):

您可以使用@unittest.skip装饰器跳过整个单元测试类。

于 2019-10-05T11:14:09.967 回答
4

对于 Python 2.7+(或使用unittest2 backport):

...

import unittest

def setUpModule():
    try:
        import something
    except ImportError as err:
        raise unittest.SkipTest(str(err))

class Tests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        try:
            import something
        except ImportError as err:
            raise unittest.SkipTest(str(err))
...
于 2016-06-17T19:21:58.767 回答
3

尝试load_tests在你的模块中定义一个自定义函数:

import unittest
try:
    (testcases)
except ImportError as e:
    def load_tests(*args, **kwargs):
        print("Failed to load tests: skipping")
        return unittest.TestSuite() # no tests
于 2012-09-19T04:25:55.860 回答
3

otus 提出的解决方案有效,并且在我看来比公认的解决方案更容易。但至少有一个缺点。如果您my_module在装饰器中查询以跳过单个测试,例如

@unittest.skipIf(my_module.support_foo, 'foo not supported')
def test_foo(self):
...

你会得到一个NameError: name 'my_module' is not defined. 解决方案是将跳过放在函数定义中:

def test_foo(self):
    if not my_module.support_foo:
        self.skipTest('foo not supported')
于 2014-09-10T14:43:11.707 回答
2

将所有子类定义放在一个块中可能很脏,但它会起作用:unittest.TestCasetry...except

import unittest
try:
    import eggs
    class Spam(unittest.TestCase):
        pass
    class Ham(unittest.TestCase):
        pass
    # ...
except ImportError:
    # print 'could not import eggs'
    pass

eggs如果导入失败并且所有这些类 ( Spam, Ham, etc.) 都被跳过,则不会定义任何子类。它不会反映在输出中(好坏取决于你想要什么)。

于 2012-09-19T04:00:51.173 回答
2

结合上述答案并使用此答案

import unittest
def module_exists(module_name):
    try:
        __import__(module_name)
    except ImportError:
        return False
    else:
        return True

class TestClass(unittest.TestCase):

    @unittest.skipUnless(module_exists("moduleA"), 'ModuleA not installed')
    def test_something(self):
        # test something with moduleA
于 2015-02-25T15:29:42.080 回答
0

您可以跳过整个课程,就像跳过单个方法一样。文档

@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
    def test_not_run(self):
        pass
于 2021-03-26T17:11:02.773 回答
0

所以这个问题已经有近十年的历史了,仍然适用!但是,其他答案都没有解决我今天遇到的问题 - 来自缺失库的测试装饰器。在这种情况下,它hypothesis和它的装饰器一样@given......所以我被迫提出了这个不太友好的替代方案:

try:
    from hypothesis import assume, example, given, strategies as st
    hypothesis_missing = False
except ImportError:
    hypothesis_missing = True
    def whatever(*args, **kwargs):
        if args or kwargs:
            return whatever
        raise ImportError("Requires hypothesis library")
    example = given = whatever
    # Then this part is ickier to be py2.7 compatible
    from six import add_move, MovedModule
    add_move(MoveModule('mock', 'mock', 'unittest.mock'))
    from six.moves import mock
    st = mock.Mock()  # Without this, things like st.integers() fail

一个 Python3 原生的解决方案只会把它收紧一点:

  import unittest
  st = unittest.mock.Mock()

然后在每个测试课上(呃)我需要:

@unittest.skipIf(hypothesis_missing, "Requires hypothesis library")

重要提示:如果没有skipIf,测试有时会默默通过-在我非常有限的测试中, raise ImportErrorinwhatever()仅捕获了大约一半。

于 2022-02-22T21:42:45.227 回答