我希望我的 Python unittest模块告诉测试运行者在某些情况下完全跳过它(例如无法导入模块或定位关键资源)。
我可以@unittest.skipIf(...)
用来跳过unittest.TestCase类,但是如何跳过整个模块?将跳过应用于每个类是不够的,因为如果模块无法导入,类定义本身可能会导致异常。
我希望我的 Python unittest模块告诉测试运行者在某些情况下完全跳过它(例如无法导入模块或定位关键资源)。
我可以@unittest.skipIf(...)
用来跳过unittest.TestCase类,但是如何跳过整个模块?将跳过应用于每个类是不够的,因为如果模块无法导入,类定义本身可能会导致异常。
如果查看 and 的定义unittest.skipIf
,unittest.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)
我发现在 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):
#...
在这里查看其他答案后,这是我想出的最佳答案。将整个测试套件嵌入到异常处理中很丑陋,但它似乎可以满足您的需求。当导入不起作用时,特别是跳过测试。
假设您正在谈论使用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装饰器跳过整个单元测试类。
对于 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))
...
尝试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')
将所有子类定义放在一个块中可能很脏,但它会起作用: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.
) 都被跳过,则不会定义任何子类。它不会反映在输出中(好坏取决于你想要什么)。
结合上述答案并使用此答案:
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()
然后在每个测试课上(呃)我需要:
@unittest.skipIf(hypothesis_missing, "Requires hypothesis library")
重要提示:如果没有skipIf
,测试有时会默默通过-在我非常有限的测试中, raise ImportError
inwhatever()
仅捕获了大约一半。