🎃

Pythonのunittest.mock.patchの対象指定方法について

2020/12/06に公開

テストを書いていると、一部の関数をモック化したいということがよくあります。Pythonではunittest.mock.patchでそれが可能です。

ただ、自分はフロントエンドの実装を行う機会が多く、jsのテストを書く場合はJestを使っているのですが、jest.mockunittest.mock.patchではモック対象とする関数の指定方法が異なるため、数時間ハマってしまいました。

備忘録ついでにその違いについて書いておきます。

Jestの場合

公式ドキュメント(https://jestjs.io/docs/ja/jest-object#jestmockmodulename-factory-options )に記載されているように、Jestの場合はモックしたいモジュールのパスを引数に指定します。

jest.mock('../moduleName', () => {
  return jest.fn(() => 42);
});

unittest.mock.patchの場合

unittest.mock.patchはデコレータであり、テスト関数の定義の上に記述します。

また、Jestとは違い、モック対象としたい関数が展開されるファイルのパスを指定する必要があります。簡単な例として、以下を考えます。

utils.py
def example_func():
  return 10
main.py
from utils import example_func

def main():
  return example_func()
  
main()
test_main.py
import unittest
from main import main

class TestMain(unittest.TestCase):
  def test_main(self):
    self.assertEqual(main(), 10)

テスト実行時にmain関数内のexample_funcをモック化したい場合、patchデコレータを以下のように書く必要があります。

def mock_example_func():
  return 1

@patch('main.example_func', mock_example_func)
def test_main(self):
    self.assertEqual(main(), 1)

importパスを引数に指定するJestとは異なり、unittest.mock.patchではモック対象の関数が展開されるファイルパスを指定する必要があります。

Jestに慣れている人からすると想定外なので、ハマって余計な時間が取られないように注意が必要です。。。

Discussion