0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pytest-mockでULIDをモックする方法

Last updated at Posted at 2025-01-22

概要

ユニットテストを書いてる中で、メソッド内で生成される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

所感

モックは奥が深いですね。

参考サイト

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?