概要
ユニットテストを書いてる中で、メソッド内で生成されるulidの値を固定したくなったのでその方法について調べました。
myapp/mock_sample.py
import ulid
class MockSampleClass:
"""クラス"""
def create_ulid():
"""ULIDを生成します。"""
return ulid.new().str # ←これをモック化したい
最終的なコード
success.py
from myapp.mock_sample import MockSampleClass
def test_mock_sample_create_ulid(mocker):
"""MockSampleClass.create_ulid()のテスト"""
excepted = "01JJ5XBKCPV0PJN1CD3C2WHPXR"
m = mocker.patch("ulid.new")
type(m).str = excepted
m.return_value = m
result = MockSampleClass.create_ulid()
assert result == excepted
調査過程
失敗1
まずは普通のモックのように書いてみます。
failed1.py
from myapp.mock_sample import MockSampleClass
def test_mock_sample_create_ulid(mocker):
"""MockSampleClass.create_ulid()のテスト"""
excepted = "01JJ5XBKCPV0PJN1CD3C2WHPXR"
mocker.patch("ulid.new", return_value=excepted)
result = MockSampleClass.create_ulid()
assert result == excepted
FAILED tests/myapp/test_mock_sample.py::test_mock_sample_create_ulid - AttributeError: 'str' object has no attribute 'str'
strメソッドがなくてエラーとなりました。
失敗2
patchの引数を変えてみます。
failed2.py
def test_mock_sample_create_ulid(mocker):
"""MockSampleClass.create_ulid()のテスト"""
excepted = "01JJ5XBKCPV0PJN1CD3C2WHPXR"
mocker.patch("ulid.new.str", return_value=excepted)
result = MockSampleClass.create_ulid()
assert result == excepted
FAILED tests/myapp/test_mock_sample.py::test_mock_sample_create_ulid - AttributeError: <bound method Api.new of <ulid.api.api.Api object at 0xffff7d149f70>> does not have the attribute 'str'
こちらもstrメソッドがなくてエラーとなりました。
エラー内容的に失敗1の方がまだ見込みがありそう。
失敗3
strのモック方法を検索して以下のサイトを見つけました。
こちらのサイトを参考に__str__のモックを見よう見まねで作ってみます。
※使い方がそもそもおかしい可能性があります。
patch()はデフォルトでMagicMockを作るらしいので、patchをインポートして使ってみます。
failed3.py
from unittest.mock import patch
from myapp.mock_sample import MockSampleClass
def test_mock_sample_create_ulid():
"""MockSampleClass.create_ulid()のテスト"""
excepted = "01JJ5XBKCPV0PJN1CD3C2WHPXR"
patcher = patch("ulid.new")
mock = patcher.start()
mock.__str__.return_value = excepted
result = MockSampleClass.create_ulid()
assert result == excepted
FAILED tests/myapp/test_mock_sample.py::test_mock_sample_create_ulid - AssertionError: assert <MagicMock name='new().str' id='281472642827072'> == '01JJ5XBKCPV0PJN1CD3C2WHPXR'
MagicMockのオブジェクトが返ってきていそうです。
感覚的にはもう一息です。
成功
前項のあと、かなり行ったり来たりしながら試行錯誤をしていたのですが、ふと__str__をモックする方法を探すのではなく、ULIDをモックする方法を調べたほうが早いのでは?と思い、検索すると以下の記事が引っかかりました。
これだーーー!!と思い、参考にさせていただいて無事解決しました。
success.py
from myapp.mock_sample import MockSampleClass
def test_mock_sample_create_ulid(mocker):
"""MockSampleClass.create_ulid()のテスト"""
excepted = "01JJ5XBKCPV0PJN1CD3C2WHPXR"
m = mocker.patch("ulid.new")
type(m).str = excepted
m.return_value = m
result = MockSampleClass.create_ulid()
assert result == excepted
所感
モックは奥が深いですね。