ユニットテストのmockを学び始める

mockは今まで「便利らしいけどなるべく使わない方が良いんでしょう?壊れやすいとも聞くし・・・」という考えもあり、積極的に書こうとすることは無かった。

そもそも現職入社までユニットテストを書く機会が殆どなく、自分で書くコードもモックを用いた方が良いコードは無かった(或いは気がついていなかった)ので書くことは無かったが、理解できた方が良いなーということで調べた。

unittest.mock

オブジェクトのメソッドが1度だけ呼び出されていることを確認するテストを書いてみる。

Python 3.12.1で検証した。

from unittest.mock import MagicMock

class Book():
    author = ""
    edition = ""
    
    def promotion(self):
        self.hoge()
    
    def hoge(self):
        pass


real = Book()
real.hoge = MagicMock()
real.promotion()
real.hoge.assert_called_once_with()

このように書くことで、`Book().promotionhogeを1度だけ呼び出したことをテストできている。 逆に、下のように real.promotion() を追加した後はreal.hoge.assert_called_once_with()が失敗することがわかる。

# 上のコードの続き

real.promotion()
real.hoge.assert_called_once_with()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/unittest/mock.py", line 955, in assert_called_once_with
    raise AssertionError(msg)
AssertionError: Expected 'mock' to be called once. Called 2 times.
Calls: [call(), call()].

公式リファレンスではこの辺りに、他のメソッド含めて説明がある。

https://docs.python.org/ja/3/library/unittest.mock.html#unittest.mock.Mock.assert_called

  • 少なくとも1回呼び出されたこと
  • 1回だけ呼び出されたこと
  • 1回呼び出され、かつ指定された引数で呼び出されたこと

などの種類があるようだった。

参考リンク

まだ全部見切れていないが、全部読むとしっかりと理解できそうなリンク。

note.crohaco.net

docs.python.org

dev.classmethod.jp

余談

書籍 単体テストの考え方/使い方 にはこの辺りのことを第5章で言及しているので、改めて読み直していく。 スタブ・モックの違いなどもどこかで整理する。