python'with'语句及其在类中的使用

时间:2012-12-14 08:11:39

标签: python unit-testing with-statement

我有一个TestCase,它使用套接字进行测试。因为即使在出现一些错误的情况下你也应该总是关闭套接字,我创建了一个抽象套接字的上下文管理器类。

测试夹具如下所示,其中MyClassToTest是要测试的实际类,它在内部使用套接字设备。

with SocketContextManager() as device:
    foo = MyClassToTest(device)
    # make tests with foo

我想避免在每个测试夹具中重复这两行,但是一致地放在setUp中。但是我该怎么做呢?以下代码

def setUp(self):
    with SocketContextManager() as device:
        self.foo = MyClassToTest(device)

不起作用,因为设备将在setUp结束时关闭。有没有办法像这样处理上下文管理器的实例化,还是我必须在每个测试夹具中重复它?

2 个答案:

答案 0 :(得分:2)

根据the documentation对于tearDown:

  

即使测试方法引发异常

,也会调用此方法

因此,您只需在setUp中打开套接字,然后在tearDown中将其关闭即可。即使您的测试用例引发异常,套接字仍将关闭。

答案 1 :(得分:1)

这是一个非常有趣的问题。正如BrenBarn指出的那样,单元测试框架并不支持你想做的事情,但在我看来,没有特别的理由让你无法适应它。 setUp / tearDown配对是其他没有生成器的语言的宿醉。

下面的代码定义了一个新的'ContextTest'类,它将setUp和tearDown方法合并到一个生成器中,该生成器构建和销毁测试的上下文。您可以将with语句与任何其他样板文件一起放入context()方法。

#!/usr/bin/python3.3
import unittest

class ContextTest(unittest.TestCase):
    """A unit test where setUp/tearDown are amalgamated into a
    single generator"""
    def context(self):
        """Put both setUp and tearDown code in this generator method
        with a single `yield` between"""
        yield

    def setUp(self):
        self.__context = self.context()
        next(self.__context)
    def tearDown(self):
        for _ in self.__context:
            raise RuntimeError("context method should only yield once")

from contextlib import closing
from urllib.request import urlopen

class MyTest(ContextTest):
    def context(self):
        with closing(urlopen('http://www.python.org')) as self.page:
            yield

    def testFoo(self):
        self.assertIsNotNone(self.page)

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