Pythonのmock_openで複数ファイルをopenするテストを書く方法のメモ
Pythonのmock_openで複数のファイルをopenするテストを書く方法のメモです。
mock_open | unittest.mock | docs.python
https://docs.python.org/ja/3/library/unittest.mock.html#mock-open
mock_open自体は、
次のように、open()をmockして単体テストを書く時に利用できます。
(ここでテスト対象としているtarget関数は、"/some/path"の内容を返却する関数)
from mock import patch, mock_open
def target():
with open('/some/path', 'r') as f:
return f.read()
def test_target():
m = mock_open(read_data="something")
with patch('builtins.open', m):
assert target() == "something"
このエントリでは、
次のように複数のファイルをopenしてテストしたい場合の対応方法を考えます。
def target_multi():
bodies = []
with open('/some/path1', 'r') as f:
bodies.append(f.read())
with open('/some/path2', 'r') as f:
bodies.append(f.read())
return bodies
ところで、
m = mock_open(read_data="something")
としてmockを作った場合、
- mock_open ... openのmockを生成するヘルパー関数
- m ... openのmock
- m.return_value = m() ... open関数の戻り値 = file handleのmock
という状態になっており、
openのmockが作られた時点でread_data(ファイルの内容)が決まってしまい、
openのmock呼び出し時のパラメータによって差し替えることができません。
そこで、
mock_openが作ってくれるfile handleのmockだけ利用して、
openのmockは、MagicMockを利用して自前で作ることにします。
from mock import patch, mock_open, MagicMock
def target_multi():
bodies = []
with open('/some/path1', 'r') as f:
bodies.append(f.read())
with open('/some/path2', 'r') as f:
bodies.append(f.read())
return bodies
def test_target_multi():
read_data_map = {
'/some/path1': 'something one',
'/some/path2': 'something two',
}
mock = MagicMock(name='open', spec=open)
mock.side_effect = lambda *args: mock_open(read_data=read_data_map[args[0]])()
with patch('builtins.open', mock):
assert target_multi() == ['something one', 'something two']
以上。