2016-09-03 17 views
0

私は、多くのChildXクラスによって継承されるParentクラスを持っています。親クラスを模擬して

class Parent(object): # the class that should be mocked 
    def __init__(self): 
     assert False # should never happen, because we're supposed to use the mock instead 

class Child1(Parent): 
    def method_1(self): 
     return 3 

class MockParent(object): # this one should replace Parent 
    def __init__(self): 
     assert True 

私はpytestで実行するテストスイートを持っている、と私は確信してこれらのテストの間に、ということにしたい、毎回ChildXがインスタンス化され、インスタンスがMockParentのメソッドの代わりにParentのものを呼ぶだろう(私は上記の例を多く簡略化したが、__init__メソッドのみが関係するわけではない)。私はやることができたすべてを一つおきChildXクラス1にパッチを適用した瞬間のために

、:

class FixturePatcher(object): 
    def __init__(self, klass): 
     self.klass = klass 
     self.patcher = None 

    def __enter__(self): 
     self.patcher = mock.patch.object(self.klass, '__bases__', (MockParent,)) 
     return self.patcher.__enter__() 

    def __exit__(self, *_, **__): 
     self.patcher.is_local = True 

@pytest.fixture() 
def mock_parent_on_child1(): 
    with FixturePatcher(Child1): 
     return Child1() 

def test_mock_child1(mock_parent_on_child1): 
    assert mock_parent_on_child1.method_1() == 3 

しかし、私は多くのChildXのクラスを持って、時にはChildYChildZのメソッド内でインスタンス化して使用されています私はそれらすべてにパッチを当てることはできません。

ParentMockParentに置き換えようと多くのことを試みましたが、いずれも機能しませんでした。私の失敗した試みのいくつかは次のとおりです:

@mock.patch('src.parent.Parent', MockParent) 
def test_mock_parent(): 
    assert Child1().method_1() == 3 # Parent's __init__ method is still called 

@mock.patch('src.parent.Parent.__getattribute__', lambda self, name: MockParent.__getattribute__(self, name)) 
def test_mock_parent(): 
    assert Child1().method_1() == 3 # same results here 

def test_mock_parent(monkeypatch): 
    monkeypatch.setattr('src.parent.Parent', MockParent) 
    assert Child1().method_1() == 3 # and still the same here 

これは可能ですか?私はpython2.7と最新バージョンのpytestmockを使用しています。

答えて

1

class Parent(object): 
    def my_method(self): 
     print 'my method' 

class Child(Parent): 
    def run(self): 
     self.my_method() 

child = Child() 

child.run() # prints: my method 

### Apply the monkeypatch: ### 

def my_method(self): 
    print 'something else' 

Parent.my_method = my_method 

child.run() # prints: something else 

あなたは可能性があり同じ方法でMockParentの方法でParentのすべてのメソッドをmonkeypatchすることもできます。これは、継承したすべての親クラスをParentから変更した場合とほぼ同じです。

EDIT:実際に

、あなたはおそらくも、それらをパッチを適用し、その将来のように、そのモジュールにParentかの定義をmonkeypatchedまさにあなたがParentのすべての既存のサブクラスのために検索した場合のために尋ね行うことができます

私はまだこれはいくつか特別な状況を逃してしまうと思うので、それぞれの方法をmonkeypatchingするとおそらく良いでしょう。

+0

私は本当にこの本当の意味でこの試みを試み、それがうまくいくかどうか教えてください! – julienc

+0

私はいくつかの回避策を実行しなければなりませんでしたが、ついにそれを作ったのです!私は '__subclasses__'に出会ったことはありません。それは魅力のように機能します! – julienc

1

いいえ、不可能です。 Child1とParentの定義(他の継承の継承を含む)は、それらのモジュールがインポートされるとすぐに実行されます。その前に入って継承階層を変更する機会はありません。

あなたができることは、定義を何らかの種類のファクトリ関数に移動することです。これは、呼び出された内容に応じてChild1の親を動的に定義することができます。

私はそれが使用されているすべての箇所 MockParentParentを交換する方法を考えることはできませんが、それはあなたが後にしているものです場合は、代わりに Parentのメソッドをモンキーパッチでき