5

假设我有以下 Python UnitTest:

import unittest

def Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # Get some resources
        ...

        if error_occurred:
            assert(False)

    @classmethod
    def tearDownClass(cls):
        # release resources
        ...

如果 setUpClass 调用失败,则不会调用 tearDownClass,因此永远不会释放资源。如果下一次测试需要资源,则在测试运行期间会出现问题。

当 setUpClass 调用失败时,有没有办法进行清理?

4

3 回答 3

6

你可以在setUpClass方法中放一个try catch,然后在except中直接调用tearDown。

def setUpClass(cls):
     try: 
         # setUpClassInner()
     except Exception, e:
        cls.tearDownClass()
        raise # to still mark the test as failed.

需要外部资源来运行单元测试是不好的做法。如果这些资源不可用并且您需要测试部分代码是否存在奇怪的错误,您将无法快速运行它。尝试区分集成测试和单元测试。

于 2013-07-09T00:55:37.077 回答
5

就像您保护其他地方的资源一样。 try-except

def setUpClass(cls):
    # ... acquire resources 
    try:
        # ... some call that may fail
    except SomeError, e:
        # cleanup here

清理可以像调用cls.tearDownClass()你的except块一样简单。 然后你可以调用assert(False)或任何你喜欢的方法提前退出测试。

于 2013-07-09T00:55:11.357 回答
3

我有一大堆测试辅助函数,它们接受一个测试实例并使用 addCleanup 干净地设置/拆除线程、临时文件等,所以我也需要 addCleanup API 来处理类级别的固定装置。我重新实现了一些 unittest doCleanup 功能来帮助我,并在课程设置期间使用模拟来修补 addCleanup()

import unittest
import logging
import mock

LOGGER = logging.getLogger(__name__)

class ClassCleanupTestCase(unittest.TestCase):
    _class_cleanups = []

    @classmethod
    def setUpClassWithCleanup(cls):
        def cleanup_fn():
            """Do some cleanup!"""
        # Do something that requires cleanup
        cls.addCleanup(cleanup_fn)

    @classmethod
    def addCleanupClass(cls, function, *args, **kwargs):
        cls._class_cleanups.append((function, args, kwargs))

    @classmethod
    def doCleanupsClass(cls):
        results = []
        while cls._class_cleanups:
            function, args, kwargs = cls._class_cleanups.pop()
            try:
                function(*args, **kwargs)
            except Exceptions:
                LOGGER.exception('Exception calling class cleanup function')
                results.append(sys.exc_info())

        if results:
            LOGGER.error('Exception(s) raised during class cleanup, re-raising '
                         'first exception.')
            raise results[0]

    @classmethod
    def setUpClass(cls):
        try:
            with mock.patch.object(cls, 'addCleanup') as cls_addCleanup:
                cls_addCleanup.side_effect = cls.addCleanupClass
                cls.setUpClassWithCleanup()
        except Exception:
            cls.doCleanupsClass()
            raise

    @classmethod
    def tearDownClass(cls):
        cls.doCleanupsClass()
于 2016-04-18T14:51:25.613 回答