[英]How to override an abstract property method without forgetting to add the property decorator in the child class?
[英]Using a class decorator, how to override a method without redefining the class?
對於使用App Engine測試平台的單元測試(使用unittest
模塊),我需要使用setUp
和tearDown
方法分別激活和停用測試平台(略有簡化):
class SomeTest(unittest.TestCase):
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
def tearDown(self):
self.testbed.deactivate()
def testSomething(self):
...
這很快成為寫的負擔。 我可以編寫一個基類TestCaseWithTestbed
,但是每當我在一個測試用例中需要自定義setUp
,我就必須記住要調用超類方法。
我認為用類裝飾器解決這個問題會更優雅。 所以我想寫:
@WithTestbed
class SomeTest(unittest.TestCase):
def testSomething(self):
...
應用此裝飾器后,應該可以神奇地激活測試平台。 那么...如何實現WithTestbed
裝飾器? 我目前有以下內容:
def WithTestbed(cls):
class ClsWithTestbed(cls):
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
cls.setUp(self)
def tearDown(self):
cls.tearDown(self)
self.testbed.deactivate()
return ClsWithTestbed
這適用於簡單的情況,但存在一些嚴重的問題:
ClsWithTestbed
並顯示在測試輸出中。 super(SomeTestClass, self).setUp()
具體測試類super(SomeTestClass, self).setUp()
無限遞歸結束,因為SomeTestClass
現在等於WithTestbed
。 我對Python的運行時類型操縱有些困惑。 那么,如何正確地做到這一點呢?
這似乎可以解決問題:
def WithTestbed(cls):
def DoNothing(self):
pass
orig_setUp = getattr(cls, 'setUp', DoNothing)
orig_tearDown = getattr(cls, 'tearDown', DoNothing)
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
orig_setUp(self)
def tearDown(self):
orig_tearDown(self)
self.testbed.deactivate()
cls.setUp = setUp
cls.tearDown = tearDown
return cls
有人看到這種方法有什么問題嗎?
這是使用子類而不是裝飾器來執行您要的操作的一種簡單方法:
class TestCaseWithTestBed(unittest.TestCase):
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
self.mySetUp()
def tearDown(self):
self.myTearDown()
self.testbed.deactivate()
def mySetUp(self): pass
def myTearDown(self): pass
class SomeTest(TestCaseWithTestBed):
def mySetUp(self):
"Insert custom setup here"
您要做的就是在測試用例中定義mySetUp
和myTearDown
而不是setUp
和tearDown
。
這樣的事情會起作用:
def WithTestbed(cls):
cls._post_testbed_setUp = getattr(cls, 'setUp', lambda self : None)
cls._post_testbed_tearDown = getattr(cls, 'tearDown', lambda self : None)
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
self._post_testbed_setUp()
def tearDown(self):
self.testbed.deactivate()
self._post_testbed_tearDown()
cls.setUp = setUp
cls.tearDown = tearDown
return cls
@WithTestbed
class SomeTest(object):
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.