这个问题的关键是帮助单元测试。如果我很忙__init__
(即__init__
进行复杂的初始化),我不能简单地实例化一个类的对象,但我需要模拟/存根在__init__
.
为了说明这个问题,这里是一个例子:
class SomeClass(object):
def __init__(self, dep1, dep2, some_string):
self._dep1 = dep1
self._dep2 = dep2
self._some_string = some_string
# I would need to mock everything here (imagine some even more
# complicated example)
for dep2element in self._dep2:
dep2element.set_dep(dep1)
self._dep1.set_some_string(some_string)
def fun1(self):
...
def fun2(self):
...
def fun3(self):
...
为了测试fun*
功能,每个测试都必须执行复杂的构造。
class TestSomeClass(TestCase):
def create_SomeClass(self, some_string):
dep1 = Mock()
# mock everything required by SomeClass' constructor
dep2 = Mock()
# mock everything required by SomeClass' constructor
return SomeClass(dep1, dep2, some_string)
def test_fun1(self):
sc = self.create_SomeClass('some string')
...
def test_fun2(self):
sc = self.create_SomeClass('some other string')
...
def test_fun3(self):
sc = self.create_SomeClass('yet another string')
...
我发现这是多余的,并且想知道如何在 python 中优雅地处理这个问题,如果不是通过从构造函数中移动工作的话。
解决方案:
正如@ecatmur 所建议的,要测试一些特定的功能,这段代码应该可以解决问题:
def test_some_method():
mobject = Mock(SomeClass)
SomeClass.fun1(mobject)
使用这种方法,所有方法都将被模拟出来。如果fun1
调用您想要执行的其他方法(例如fun2
),您可以这样做:
def test_some_method():
mobject = Mock(SomeClass)
mobject.fun2 = SomeClass.fun2.__get__(mobject)
SomeClass.fun1(mobject)
SomeClass.fun2.__get__(mobject)
将产生instancemethod
将提供正确绑定的内容。
¡万岁蟒蛇!
原始问题:
最初的问题集中在将完成的工作__init__
转移到单独的init
方法和围绕该方法的不同问题上。我通常的做法是做这个
class SomeClass(object):
def __init__(self, dep1, dep2, some_string)
self._dep1 = dep1
self._dep2 = dep2
# lots of mumbo-jumbo here...
变成这个
class SomeClass(object):
def __init__(self, dep1, dep2)
self._dep1 = dep1
self._dep2 = dep2
def initiate(self, some-string)
# lots of mumto-jumbo here...
普遍的看法是,将工作移出__init__
不是一种常见的做法,对于经验丰富的 Python 开发人员来说毫无意义。