简体   繁体   English

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

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

I would like my Python unittest module to tell the test runner to skip it entirety under some situations (such as being unable to import a module or locate a critical resource).我希望我的 Python unittest模块告诉测试运行者在某些情况下完全跳过它(例如无法导入模块或定位关键资源)。

I can use @unittest.skipIf(...) to skip a unittest.TestCase class, but how do I skip the entire module ?我可以使用@unittest.skipIf(...)跳过unittest.TestCase class,但是如何跳过整个模块 Applying skips to every class is not sufficient because the class definitions themselves could cause exceptions if a module fails to import.对每个 class 应用跳过是不够的,因为如果模块无法导入,class 定义本身可能会导致异常。

If you look at the definition of unittest.skipIf and unittest.skip , you can see that the key is doing raise unittest.SkipTest(reason) when the test is executed.如果查看unittest.skipIfunittest.skip的定义,可以看到关键是在执行测试时执行raise unittest.SkipTest(reason) If you're okay with having it show up as one skipped test instead of several in the testrunner, you can simply raise unittest.SkipTest yourself on import:如果您可以将它显示为一个跳过的测试而不是 testrunner 中的几个,您可以简单地在导入时自己提高unittest.SkipTest

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

Running with nosetests -v gives:使用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)

I found that using skipTest in setUp worked well.我发现在 setUp 中使用 skipTest 效果很好。 If you need a module imported, you use a try block to set eg module_failed = True, and in setUp call skipTest if it's set.如果您需要导入模块,您可以使用 try 块来设置例如 module_failed = True,如果设置了,则在 setUp 中调用 skipTest。 This reports the correct number of test skips with only a short try block needed:这报告了正确的测试跳过次数,只需要一个简短的 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):
            #...

After looking at the other answers here, this is the best answer I've come up with.看了这里的其他答案后,这是我想出的最佳答案。 It's ugly, embedding the whole test suite in the exception handling, but it appears to do what you want.这很丑陋,将整个测试套件嵌入异常处理中,但它似乎可以满足您的需求。 Specifically skipping the tests when the imports don't work.特别是在导入不起作用时跳过测试。

Assuming you're talking about using nosetests -x for running the tests it should carry on past the tests that skip, at least it appeared to when I tried it.假设您正在谈论使用 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()

If the import fails it replaces the test run with a single test that simply skips.如果导入失败,它将用简单跳过的单个测试替换测试运行。 I've also attempted to make sure that it doesn't swallow any exceptions unintentionally.我还试图确保它不会无意中吞下任何异常。 This solution owes a lot to all the other answers and comments to the question.该解决方案很大程度上归功于该问题的所有其他答案和评论。

If you run it in verbose mode you will see this when it skips,如果你在详细模式下运行它,你会在它跳过时看到这个,

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

You can skip the whole unit test class by using the @unittest.skip decorator.您可以使用@unittest.skip装饰器跳过整个单元测试类。

Try defining a custom load_tests function in your module:尝试在你的模块中定义一个自定义的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

The solution proposed by otus works and is easier than the accepted solution in my opinion.在我看来,otus 提出的解决方案比公认的解决方案更有效。 But there is at least one downside.但至少有一个缺点。 If you query my_module in a decorator to skip a single test such as如果您在装饰器中查询my_module以跳过单个测试,例如

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

you will get a NameError: name 'my_module' is not defined .你会得到一个NameError: name 'my_module' is not defined The solution is put the skip inside the function definition:解决方案是将跳过放在函数定义中:

def test_foo(self):
    if not my_module.support_foo:
        self.skipTest('foo not supported')

For Python 2.7+ (or using the unittest2 backport):对于 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))
...

It might be dirty to put all the unittest.TestCase subclass definitions in a try...except block, but it would work:将所有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

None of the sub-classes would be defined if the eggs import fails and all those classes ( Spam, Ham, etc. ) get skipped.如果eggs导入失败并且所有这些类( Spam, Ham, etc. )都被跳过Spam, Ham, etc.则不会定义任何子类。 It would not be reflected in the output (good or bad depending on what you want).它不会反映在输出中(好或坏取决于你想要什么)。

Combining the mentioned answers and using this answer :结合上述答案并使用此答案

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

You can skip the whole class just like skipping individual methods.您可以像跳过单个方法一样跳过整个类。 Documentation 文档

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

So this question is nearly a decade old, and still applicable, However.所以这个问题已经有近十年的历史了,但仍然适用。 none of the other answers addressed the problem I was having today - decorators on the tests coming from the missing library, In this case, it was hypothesis and its decorators like @given ... So I was forced to whip up this less-than-friendly alternative:其他答案都没有解决我今天遇到的问题 - 来自缺失库的测试装饰器,在这种情况下,它是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

A Python3-native solution would just tighten it up a little:一个 Python3 原生的解决方案只会把它收紧一点:

  import unittest
  st = unittest.mock.Mock()

Then on each testing class (ugh) I needed:然后在每次测试 class (呃)我需要:

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

IMPORTANT NOTE: Without the skipIf , the tests will sometimes silently pass - the raise ImportError in whatever() only caught about half of them in my very limited testing.重要说明:如果没有skipIf ,测试有时会默默通过——whatever whatever()中的raise ImportError在我非常有限的测试中只捕获了大约一半。

If you are just looking to skip an entire module/submodule then place the following code in the relevant __init__.py .如果您只是想跳过整个模块/子模块,请将以下代码放在相关的__init__.py中。 Like the other solutions, this will have one message for all skipped tests.与其他解决方案一样,这将为所有跳过的测试提供一条消息。

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