<p>像您这样调用<code>__enter__</code>和<code>__exit__</code>的问题并不是您已经这样做了:它们可以在<code>with</code>语句之外调用。问题是,如果发生异常,代码没有正确调用对象的<code>__exit__</code>方法的规定。</p>
<p>因此,方法是使用一个decorator将对原始方法的调用包装在一个<code>with</code>语句中。短元类可以透明地将decorator应用于类中名为test*的所有方法-</p>
<pre><code># -*- coding: utf-8 -*-
from functools import wraps
import unittest
def setup_context(method):
# the 'wraps' decorator preserves the original function name
# otherwise unittest would not call it, as its name
# would not start with 'test'
@wraps(method)
def test_wrapper(self, *args, **kw):
with GetSlot() as slot:
self._slot = slot
result = method(self, *args, **kw)
delattr(self, "_slot")
return result
return test_wrapper
class MetaContext(type):
def __new__(mcs, name, bases, dct):
for key, value in dct.items():
if key.startswith("test"):
dct[key] = setup_context(value)
return type.__new__(mcs, name, bases, dct)
class GetSlot(object):
def __enter__(self):
return self
def __exit__(self, *args, **kw):
print "exiting object"
def doStuff(self):
print "doing stuff"
def doOtherStuff(self):
raise ValueError
def getSomething(self):
return "a value"
def UnderTest(*args):
return args[0]
class MyTestCase(unittest.TestCase):
__metaclass__ = MetaContext
def testFirstThing(self):
u = UnderTest(self._slot)
u.doStuff()
self.assertEqual(u.getSomething(), 'a value')
def testSecondThing(self):
u = UnderTest(self._slot)
u.doOtherStuff()
self.assertEqual(u.getSomething(), 'a value')
unittest.main()
</code></pre>
<p>(我还包括了“GetSlot”的模拟实现,以及示例中的方法和函数,这样我自己就可以测试我建议的decorator和元类)</p>