5

インポートされたモジュールのコードを変更せずに、2 つのインポートが深い Python クラスをモックするにはどうすればよいですか? HTTPClient() をインポートする Web ユーティリティのライブラリをインポートするとします。ファイル web_utils.py を変更せずに、HTTPClient をモックして値を返す単体テストを作成するにはどうすればよいでしょうか? DataHandler でデータ操作を使用したい (モックアウトするのではなく)が、HTTPClient を実際に Web に接続したくありません。

これは可能ですか?Python にモンキー パッチがあることを考えると、そうあるべきだと思われます。または、代替/より良い方法はありますか? 私はまだモッキングプロセスを考え出しています.インポートを変更することはあまりありません.

# someLib/web_utils.py
from abc.client import SomeHTTPClient # the class to replace

def get_client():
    tc = SomeHTTPClient(endpoint='url') # fails when I replace the class
    return tc

class DataHandler(object):
    def post_data(someURL, someData):
        newData = massage(someData)
        client = get_client()
        some_response = client.request(someURL, 'POST', newData)
        return some_response

# code/myCode.py
from someLib.web_utils import DataHandler

dh = DataHandler()
reply = dh.post_data(url, data)

# tests/myTests.py
from django.test.testcases import TestCase
from mock import Mock

class Mocking_Test(TestCase):
    def test_mock(self):
        from someLib import web_utils
        fakeClient = Mock()
        fakeClient.request = web_utils.SomeHTTPClient.request # just to see if it works
        web_utils.SomeHTTPClient = fakeClient
        dh = DataHandler()
        reply = dh.post_data(url='somewhere', data='stuff')

更新 -get_client()機能を追加しました。@spicavigoの答えは正しい軌道に乗っていると思います-SomeHTTPClientクラスを置き換えているようです。しかし、何らかの理由で、クラスはオブジェクトをインスタンス化しません (エラーは、「型でなければならず、モックではありません」)。Mock()クラスではなく、作成されたオブジェクトになる方法もわかりません。そのため、その部分を機能させる方法がわかりません。

4

3 に答える 3

4

これをmyTest.pyに追加して、試してみてください

from someLib import web_utils
web_utils.SomeHTTPClient = <YOUR MOCK CLASS>
于 2012-09-06T13:30:50.353 に答える
2

最終的に機能したのは次のとおりです。

class Mocking_Test(TestCase):
    def test_mock(self):
        def return_response(a, b, c, *parms, **args):
            print "in request().return_response"
            class makeResponse(object):
                status = 200
                reason = "making stuff up"
            return makeResponse()

        fakeClient = Mock()
        fakeClient.return_value = return_response

        #with patch('abc.client.SomeHTTPClient') as MockClient: # not working.
        with patch('abc.client.SomeHTTPClient.request', new_callable=fakeClient):
            dh = DataHandler()
            reply = dh.post_data(url='somewhere', data='stuff')

私は元の投稿で正しい軌道に乗ってpatchいましたが、パッチを正しく適用していませんでした。また、クラス全体を置き換えるのではなく、requestクラスの関数だけを置き換えます (実際に HTTP 要求を行うことを避けるために、モック アウトする必要があるのはこれだけです)。

于 2012-09-06T18:15:14.540 に答える
-1

これはまさにあなたが望んでいたものではないことはわかっていますが、モッククラスを作成した後、コードをよりクリーンにするために、このようなことをするだけです(bashシェルで、そうでなければ、ファイルが1つある場合は、検索して実行するだけです交換)

find . -name "*.py" -type f -exec sed -i "s/<old_class>/<mock_class>/g" '{}' \;

これにより、古いクラスのすべてのインスタンスが新しいクラスに置き換えられます。個人的には、コードがよりクリーンになると思います。すべての .py ファイルではなく 1 つのファイルだけが必要な場合は、-name を "file.py" に変更します。

于 2012-09-06T14:18:07.190 に答える