2016-03-03 4 views
6

私はエントリポイント関数は、オブジェクト上の他のいくつかのメソッドを呼び出しますから、私はunmocked残るしたいオブジェクトにmainそれを呼び出す必要があり:どのようにしてオブジェクトを修正し、すべてのメソッドが1つを除いたモックされるようにしますか?

class Thing(object): 

    def main(self): 
     self.alpha() 
     self.bravo() 

    def alpha(self): 
     self.charlie() 

    def bravo(self): 
     raise TypeError("Requires Internet connection!") 

    def charlie(self): 
     raise Exception("Bad stuff happens here!") 

を。これは、手動でモックにはかなり簡単です:

thing = Thing() 
thing.alpha = MagicMock() 
thing.bravo = MagicMock() 

そして私は、私は彼らが、扱っていることを確認するアルファとブラボーで副作用を設定することができ、アルファとブラボーの両方が一度呼ばれていることを確認するためにテストすることができますなどなど私は何

アボを心配utは、コード定義が変更され、誰かがmaincharlieコールを追加した場合です。それは嘲笑されていないので、今は副作用が感じられるでしょう(そして、ファイルへの書き込み、データベースへの接続、インターネットからのものの取り出しなど)、単純な例外はテストが今であることを警告しません悪い)。

私のモックオブジェクトは、私が言うべきもの以外の方法を呼んでいないことを確認することでした(あるいはテスト例外を発生させる)。私がしなければしかし、このような何か:それは他のメソッドを呼び出していないので、

MockThing = create_autospec(Thing) 
thing = Thing() 
thing.main() 

print thing.method_calls 
# [calls.main()] 

その後mainも嘲笑されます。どのように私はすべての方法しかし、メインの方法をモックできますか? (私はmethod_callsを[calls.alpha(), calls.bravo()]にしたいと思います)。

編集:ハッキングはまあ

を回答については、私は本当にハック解決策を持っているが、私はこれよりも良い答えはそこにあると思います。基本的に私は、元のクラス(Python bind an unbound method

MockThing = create_autospec(Thing) 
thing = MockThing() 
thing.main = Thing.ingest.__get__(thing, Thing) 
thing.main() 

print thing.method_calls 
# [calls.alpha(), calls.bravo()] 

からメソッドを再バインドしかし、機能記述子を使用するよりも簡単な解決策が存在しなければなりません!

+0

「オブジェクトには属性「取り込み」がありません」というエラーが表示されます。私はPython 2.7を使用しています –

答えて

0

ユニットテストを統合テスト/機能テストにするか、特定のユニット以外の他のテストを心配しているようです。

ユニットテストの場合Thingテストしていない部品を嘲笑する必要があります。しかし、Thingが(DBなどの)他のものとどのように統合されているかをテストしているなら、実際のThingを試してみてください。

また、これは依存性の注入は、多くの意味を作る場所がこのような何かになるため、次のとおりです。

class Thing: 
    def __init__(self, db, dangerous_thing): 
     self.db = db 
     self.dangerous_thing = dangerous_thing 

    #.... 

    def charlie(self): 
     foxtrot = self.dangerous_thing.do_it() 

をそんなに出Thingをテストしている間、今あなたがdangerous_thingのためにモックに渡すことができますあなたはについて本当にのことを心配する必要はありません。dangerous_thing。とにかく後、それを分離した方が良いです、あなたのテストを書く

mt = Mock(Thing) 
Thing.main(mt) 
print(mt.mock_calls) 

[call.alpha(), call.bravo()] 

:私はもののこれらの奇妙な種類をしたとき

+0

あなたの助言、ウェイン - ありがとうございます - しかし、これは私の質問に答えることはありません。 – bbengfort

3

ことのように私は静的メソッドの参照を呼び出すために使用されるモックうクラスの実際のメソッドを呼び出しますいくつかの共同作業者を使って、あなたがテストしたいものとは別のものを分離します。これらのテストを使用してプロダクションコードリファクタをリードし、最後にテストをリファクタリングしてこれらのダーティテストを削除します。

+0

メソッドの静的なバージョンを呼び出すと、ここで助けになりました。まことにありがとうございます! –

1

私は同じ問題を抱えていましたが、私はそれを行う方法を考えました。私は満足しています。 mock_thingに属する実際の「メイン」関数を呼び出すmock_thingになります

import mock 

mock_thing = mock.create_autospec(Thing) 
mock_thing.main = lambda x: Thing.main(mock_thing, x) 

これが、mock_thing.alpha()とmock_thing.betaは()の両方が呼び出されます。上記のように次の例では、あなたのことクラスを使用していますモックとして! (xを関数に渡すパラメータで置き換えます)。

うまくいけば、あなたのためにうまくいきます!

関連する問題