この質問の鍵は、単体テストを支援することです。忙しい場合__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 開発者にとって意味がないというものでした。