Open3
モックしたい(unittest.mock)
from unittest.mock import MagicMock
PySerialをモックする
read_data.py
def read_data(port: serial.Serial):
data = port.readline().decodt("UTF-8").strip().split()
return data
- USBポートに接続した測定器からデータを読み出す関数
- 測定器からは
値1 値2 値3 値4
のようなスペース区切りの文字列が送られてくる
test_read_data.py
from unittest.mock import MagicMock
def test_read_data():
mock_port = MagicMock()
mock_port.readline().decode.return_value = "値1 値2 値3 値4"
data = read_data(mock_port)
assert isinstance(data, list)
- ユニットテストでは、ポートに接続せずにテストしたい
-
Serial
オブジェクトをMagicMock
で作成する - テストしたい関数と同じ処理を
MagicMock
オブジェクトに追加する -
return_value
に返したい値を設定する - ユニットテスト用の関数の引数に
MagicMock
オブジェクトを指定する
pathlib.Pathをモックする
from pathlib import Path
import serial
def save_data(fname: Path, port: serial.Serial, max_rows: int):
events = []
with fname.open("a") as f:
for _ in range(max_rows):
event = read_data(port)
events.append(event)
f.write(events + "\n")
f.flush()
return events
-
max_rows
行のデータをファイルに保存する関数
from unittest.mock import MagicMock, patch, mock_open
@patch("pathlib.Path.open", new_callable=mock_open)
def test_save_data(mock_open):
# Pathオブジェクトをモックする
fname = Mock()
# Serialオブジェクトをモックする
port = Mock()
port.readline().decode.return_value = "値1 値2 値3 値4"
max_rows = 5
events = save_data(fname, port, max_rows)
# 検証
assert len(events) == max_rows
mock_open.assert_called_once_with("a")
handle = mock_open()
assert handle.write.call_count == max_rows
assert handle.flush.call_count == max_rows
- ファイル操作がある関数をテストする場合、ファイルを開く関数をモックする
-
pathlib
の場合は、pathlib.Path.open
をmock_open
に置き換える -
@patch
デコレータで上書きする -
mock_open.assert_called_once_with("a")
で、fname.open("a")
が1回だけ呼ばれたことごチェック -
関数名.call_count
で該当する関数を呼び出した回数を確認できる