在 python 中,是否有在设置/拆卸中使用上下文管理器的好习惯 [英] In python, is there a good idiom for using context managers in setup/teardown

查看:28
本文介绍了在 python 中,是否有在设置/拆卸中使用上下文管理器的好习惯的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现我在 Python 中使用了大量上下文管理器.但是,我已经使用它们测试了许多东西,我经常需要以下内容:

class MyTestCase(unittest.TestCase):def testFirstThing(self):以 GetResource() 作为资源:u = UnderTest(资源)u.doStuff()self.assertEqual(u.getSomething(), '一个值')def testSecondThing(self):以 GetResource() 作为资源:u = UnderTest(资源)u.doOtherStuff()self.assertEqual(u.getSomething(), '一个值')

当这进行许多测试时,这显然会变得无聊,所以本着 SPOT/DRY(单点真理/不要重复自己)的精神,我想将这些部分重构到测试中 setUp()tearDown() 方法.

然而,试图这样做导致了这种丑陋:

 def setUp(self):self._resource = GetSlot()self._resource.__enter__()def 拆解(自我):self._resource.__exit__(None, None, None)

必须有更好的方法来做到这一点.理想情况下,在 setUp()/tearDown() 中,每个测试方法没有重复的位(我可以看到在每个方法上重复装饰器是如何做到的).

将被测对象视为内部对象,将 GetResource 对象视为第三方对象(我们不会更改).

我在这里将 GetSlot 重命名为 GetResource——这比具体情况更通用——上下文管理器是对象打算进入锁定的方式状态和退出.

解决方案

如何重写 unittest.TestCase.run() 如下图所示?这种方法不需要调用任何私有方法或对每个方法做一些事情,这正是提问者想要的.

from contextlib import contextmanager导入单元测试@contextmanagerdef resource_manager():产量'foo'类 MyTest(unittest.TestCase):def运行(自我,结果=无):使用 resource_manager() 作为资源:self.resource = 资源超级(MyTest,自我).运行(结果)定义测试(自我):self.assertEqual('foo', self.resource)单元测试.main()

这种方法还允许将 TestCase 实例传递给上下文管理器,如果您想在那里修改 TestCase 实例.

I am finding that I am using plenty of context managers in Python. However, I have been testing a number of things using them, and I am often needing the following:

class MyTestCase(unittest.TestCase):
  def testFirstThing(self):
    with GetResource() as resource:
      u = UnderTest(resource)
      u.doStuff()
      self.assertEqual(u.getSomething(), 'a value')

  def testSecondThing(self):
    with GetResource() as resource:
      u = UnderTest(resource)
      u.doOtherStuff()
      self.assertEqual(u.getSomething(), 'a value')

When this gets to many tests, this is clearly going to get boring, so in the spirit of SPOT/DRY (single point of truth/dont repeat yourself), I'd want to refactor those bits into the test setUp() and tearDown() methods.

However, trying to do that has lead to this ugliness:

  def setUp(self):
    self._resource = GetSlot()
    self._resource.__enter__()

  def tearDown(self):
    self._resource.__exit__(None, None, None)

There must be a better way to do this. Ideally, in the setUp()/tearDown() without repetitive bits for each test method (I can see how repeating a decorator on each method could do it).

Edit: Consider the undertest object to be internal, and the GetResource object to be a third party thing (which we aren't changing).

I've renamed GetSlot to GetResource here—this is more general than specific case—where context managers are the way which the object is intended to go into a locked state and out.

解决方案

How about overriding unittest.TestCase.run() as illustrated below? This approach doesn't require calling any private methods or doing something to every method, which is what the questioner wanted.

from contextlib import contextmanager
import unittest

@contextmanager
def resource_manager():
    yield 'foo'

class MyTest(unittest.TestCase):

    def run(self, result=None):
        with resource_manager() as resource:
            self.resource = resource
            super(MyTest, self).run(result)

    def test(self):
        self.assertEqual('foo', self.resource)

unittest.main()

This approach also allows passing the TestCase instance to the context manager, if you want to modify the TestCase instance there.

这篇关于在 python 中,是否有在设置/拆卸中使用上下文管理器的好习惯的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆