1. ホーム
  2. python

[解決済み] 単体テスト用パッチで2つの関数をモック化する

2023-02-20 10:45:05

質問

ユニットテストをしたい関数があるのですが、その関数は他の2つの関数を呼び出します。私はどのようにパッチを使用して適切に同時に両方の関数をモックすることができるかわからない。私は以下に私が意味することの例を提供しました。私がnosetestsを実行するとき、テストは合格しますが、私はこれを行うためのクリーンな方法があるはずだと感じており、私はf.close()に関する部分を本当に理解していません...。

ディレクトリ構造は次のようになります。

program/
  program/
    data.py
  tests/
    data_test.py

data.py:

import cPickle

def write_out(file_path, data):
    f = open(file_path, 'wb')
    cPickle.dump(data, f)
    f.close()

data_test.pyです。

from mock import MagicMock, patch

def test_write_out():
    path = '~/collection'
    mock_open = MagicMock()
    mock_pickle = MagicMock()
    f_mock = MagicMock()
    with patch('__builtin__.open', mock_open):
        f = mock_open.return_value
        f.method.return_value = path
        with patch('cPickle.dump', mock_pickle):
            write_out(path, 'data')
            mock_open.assert_called_once_with('~/collection', 'wb')
            f.close.assert_any_call()
            mock_pickle.assert_called_once_with('data', f)

結果

$ nosetests
.
----------------------------------------------------------------------
Ran 1 test in 0.008s
OK

どのように解決するのですか?

パッチデコレータを使い、このようにネストすることでテストを簡略化することができます(これらは MagicMock オブジェクトになります)。

@patch('cPickle.dump')
@patch('__builtin__.open')
def test_write_out(mock_open, mock_pickle):
    path = '~/collection'
    f = mock_open.return_value
    f.method.return_value = path

    write_out(path, 'data')

    mock_open.assert_called_once_with('~/collection', 'wb')
    mock_pickle.assert_called_once_with('data', f)
    f.close.assert_any_call()

への呼び出しは MagicMock のインスタンスを呼び出すと、新しい MagicMock のインスタンスを返すので、他のモックオブジェクトと同じように返された値が呼び出されたことを確認することができます。この場合 fMagicMock という名前の 'open()' (試しに f ).