ユニットテストでは、開発環境から呼び出せない処理はモックに差し替えてテストしたい。
たとえば、外部のAPIの呼び出しやファイルの読み書きなどをモックにすることが多い。
モックにするやり方が色々あるので、簡単にまとめる。
インスタンスのメソッドをMagicMockで置き換える
以下のhoge_func
メソッドをモックにしてみる。
class Hoge: def hoge_func(self): return 'called func'
hoge_func
メソッドにMagicMockを設定してみる。
メソッドがモックに置き換わり、戻り値が'called mock'
になっている。
def test(self): hoge = Hoge() hoge.func = MagicMock(return_value='called mock') self.assertEqual(hoge.func(), 'called mock')
クラスメソッドをMagicMockで置き換える
クラスメソッドもモック化できる。
たとえば、以下のようにクラスメソッドを持つクラスがあったとする。
class Hoge2: @classmethod def class_func(cls): # 1から10のランダムな数値を返す return random.randint(1, 10)
クラスメソッドをMagicMockで置き換えれば、動作を変えることができる。
def test(self): print(Hoge2.class_func()) # 3 Hoge2.class_func = MagicMock(return_value=99) print(Hoge2.class_func()) # 99
対象メソッドのパスを指定してモック化する(patch)
ユニットテストで、モック化したいインスタンスのメソッドにアクセスできることは少ないと思う。
大抵は、テストしたいモジュールから呼び出される別のモジュールをモック化したいはず。
たとえば、以下のようなコードを考えてみる。
class Hoge: def hoge_func(self): # 1から10のランダムな数値を返す return random.randint(1, 10) class Fuga: def __init__(self): self.hoge = Hoge() def fuga_func(self): val = self.hoge.hoge_func() # 2倍にして返す return val * 2
Fugaクラスはインスタンス変数にHogeのオブジェクトを持っている。
Fugaクラスのfuga_func
のテストをしたい場合、Hogeクラスのhoge_func
の返す値がランダムなのでテストし辛い。
このような場合、patchでhoge_func
をモック化すると楽にテストできる。
def test(self): with patch('module.Hoge.hoge_func') as hoge_func_mock: # hoge_funcの戻り値を10に固定する hoge_func_mock.return_value = 10 fuga = Fuga() self.assertEqual(fuga.fuga_func(), 20)
patchは以下のようにデコレータとして書くこともできる。
@patch('module.Hoge.hoge_func', return_value=5) def test(self, hoge_func_mock): fuga = Fuga() self.assertEqual(fuga.fuga_func(), 10)
デコレータで指定したモックはユニットテストの引数として記載する必要がある。(hoge_func_mock
の部分)
複数のデコレータを設定した場合は、 デコレータでで書いた逆順 に引数を書く必要があるので注意する。