繁体   English   中英

如何在运行时跳过整个 Python 'unittest' 模块?

[英]How do I skip a whole Python 'unittest' module at run time?

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

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

如果查看unittest.skipIfunittest.skip的定义,可以看到关键是在执行测试时执行raise unittest.SkipTest(reason) 如果您可以将它显示为一个跳过的测试而不是 testrunner 中的几个,您可以简单地在导入时自己提高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)

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

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):
            #...

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

假设您正在谈论使用 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'
@unittest.skip('comments_for_skipping_unit_tests')
class MyTests(unittest.TestCase):
def setUp(self):
    pass

def test_something(self):

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

尝试在你的模块中定义一个自定义的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

在我看来,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')

对于 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))
...

将所有unittest.TestCase子类定义放在try...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. )都被跳过Spam, Ham, etc.则不会定义任何子类。 它不会反映在输出中(好或坏取决于你想要什么)。

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

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

您可以像跳过单个方法一样跳过整个类。 文档

@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
    def test_not_run(self):
        pass

所以这个问题已经有近十年的历史了,但仍然适用。 其他答案都没有解决我今天遇到的问题 - 来自缺失库的测试装饰器,在这种情况下,它是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()

然后在每次测试 class (呃)我需要:

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

重要说明:如果没有skipIf ,测试有时会默默通过——whatever whatever()中的raise ImportError在我非常有限的测试中只捕获了大约一半。

如果您只是想跳过整个模块/子模块,请将以下代码放在相关的__init__.py中。 与其他解决方案一样,这将为所有跳过的测试提供一条消息。

import unittest

raise unittest.SkipTest("Don't run these tests because x, y, and z")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM