PythonのMagicMockで"name"をmockする方法
PythonのMagicMockでnameの値をmockしてassertすると失敗するので、その対処方法について。
対処前
以下のようなクラスとテストコードがあり、JobをmockしてPersonのテストを行いたいとする。
class Job:
def __init__(self, name):
self.name = name
class Person:
def __init__(self, job_name):
self.job = Job(name=job_name)
def get_job_name(self):
return self.job.name
from unittest.mock import MagicMock
import pytest
from src.sample import Person
@pytest.fixture(scope="function")
def job_mock():
return MagicMock(name="my_job")
def test_get_job_name(job_mock):
person = Person(job_name=job_mock.name)
assert person.get_job_name() == "my_job"
こんなコードを書くと、以下のようにassertで失敗する。
$ pytest test_sample.py
...
job_mock = <MagicMock name='my_job' id='4330745872'>
def test_get_job_name(job_mock):
person = Person(job_name=job_mock.name)
> assert person.get_job_name() == "my_job"
E AssertionError: assert <MagicMock name='my_job.name' id='4330800272'> == 'my_job'
E + where <MagicMock name='my_job.name' id='4330800272'> = <bound method Person.get_job_name of <src.sample.Person object at 0x101e8e2d0>>()
E + where <bound method Person.get_job_name of <src.sample.Person object at 0x101e8e2d0>> = <src.sample.Person object at 0x101e8e2d0>.get_job_name
tests/test_sample.py:14: AssertionError
エラーから、assertの左辺がMagicMockのinstanceになってしまっていることがわかる。
対処方法
この挙動の原因はunittestのドキュメントにある通り、Mockクラスのコンストラクタで指定されたnameはmockインスタンスの名前になってしまうため。
これはMockインスタンスの作成後にnameをアトリビュートとしてセットしてあげることで回避できる。
...
@pytest.fixture(scope="function")
def job_mock():
- return MagicMock(name="my_job")
+ mock = MagicMock()
+ mock.name = "my_job" # mock.configure_mock(name="my_job")でもOK
+ return mock
...