24

mockPythonでいくつかの単体テストを書くために使用しようとしています。

たとえば、次のクラスがあります。

class TCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(1024).strip()

handleそして、メソッドをテストしたいだけです。について何も想定する必要はありませんsocketserver.BaseRequestHandler。たとえば、引数でhandle呼び出していることをアサートしたいと思います。モックでそのようなことをすることは可能ですか?つまり、基本クラスをモックに置き換えますか? それとも私はその考えから外れていますか?recv1024socketserver.BaseRequestHandler


ecatmurの答えで(ありがとう!)私は最初に次のことを試しました:

patcher = patch.object(TCPHandler, '__bases__', (Mock,))
with patcher:
    patcher.is_local = True
    handler = TCPHandler()
    handler.handle()

しかし、今handleは呼び出されなくなり、次のようになりdir(handler)ます。

['assert_any_call', 'assert_called_once_with', 'assert_called_with', 'assert_has_calls', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called', 'configure_mock', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect']

type(handler)与える <class 'mock.TCPHandler'>

基本クラスにパッチを適用すると、派生クラスもモックに変わると解釈します。


私は今、別のアイデアを試してみました:

mock = MagicMock()
TCPHandler.handle(mock)
#assertions

ただし、モックは呼び出されないようです。

4

3 に答える 3

26

派生クラスの にパッチを適用することでこれを行うことができます__bases__:

def test_derived():
    patcher = mock.patch.object(Derived, '__bases__', (mock.Mock,))
    with patcher:
        patcher.is_local = True
        d = Derived()
        print d.foo()

パッチを元に戻すときに呼び出しを試行しないようにするために、is_localハックが必要です。mock.patchdelattr

于 2012-08-31T18:45:36.810 に答える
6

問題は、テストしたい実際のコードをモックしようとしていることにあると思います。そのコードによって呼び出されているオブジェクトではなく。handle メソッドが self.request で recv メソッドを呼び出すかどうかを確認したい場合は、recv メソッドをモックアウトします。

def test_tcp_handler_method(self):

    handler = TCPHandler()
    handler.request = Mock()

    handler.handle()

    self.assertTrue(handler.request.recv.called)
    self.assertEqual(handler.request.recv.call_args[0], 1024)

ハンドラーをインスタンス化するために追加のセットアップを行う必要があるかもしれませんが、基本的な考え方は明確です。

于 2012-09-04T06:11:08.923 に答える
6

それが最善の解決策かどうかはわかりませんが、type()を使用して別の親を持つ以前のクラスを再定義しました。patch_parent()親モックを持つクラスを返すという関数を作成しました。

from contextlib import contextmanager

@contextmanager
def patch_parent(class_):
    """
    Mock the bases
    """
    yield type(class_.__name__, (Mock,), dict(class_.__dict__))

patch_parentこの後、次のように使用できます。

class Bar():
   def method(self, param1, param2...):
       ...

class Foo(Bar):
   pass


>>> with patch_parent(Foo) as MockFoo:
...     f = MockFoo()
...     print f
...     print f.method()
... 
<Foo id='15488016'>
<Foo name='mock.method()' id='15541520'>
>>> s = Foo()
>>> s.method()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 3 arguments (1 given)

MockFooクラスにはまだクラスのメソッドがあり、親がクラスFooになっているため、親で定義されたメソッドはありません Mock

于 2014-07-04T15:25:52.687 に答える