【Python】単体試験 / unittest ~ mock編 ~

■ はじめに

https://dk521123.hatenablog.com/entry/2019/10/02/223658
https://dk521123.hatenablog.com/entry/2021/03/31/000000

の続き。

今回は、unittest の Mock を使ってみる。
これで、ほとんど標準で単体試験ができる。

目次

【1】unittest.mock
【2】MagicMock
 1)サンプル
【3】patch()
 1)サンプル
【4】サンプル
 例1:例外を発生させるモック

【1】unittest.mock

* 標準の単体試験ツール unittest の Mock

公式サイト
https://docs.python.org/ja/3/library/unittest.mock.html

【2】MagicMock

* MagicMockクラスは、Mockクラスのサブクラス
* Mockクラス機能+Pythonの持つ全ての特殊メソッドをサポート
 => 基本、MagicMockを使う方がいい

1)サンプル

* 以下の関連記事の
「2)継承したクラスの単体試験」をベースにする
 => 「[親クラス] base_demo_class.py」
  「[テスト対象クラス] demo_class.py」
  は、変更していないので、省略。

https://dk521123.hatenablog.com/entry/2022/07/30/154233

import unittest
from unittest.mock import patch, MagicMock
from demo_class import DemoClass

class TestDemoClass(unittest.TestCase):
  # テストメソッドを実行するたびに呼ばれる
  def setUp(self):
    print('setUp')
    self.target_class = DemoClass()
    # ★ここに注目★
    self.target_class.say_hello = MagicMock(return_value='Hello from Mock')

  # 1) say_hello
  def test_say_hello(self):
    self.assertEqual(
      self.target_class.say_hello(),
      'Hello from Mock')

if __name__ == '__main__':
  unittest.main()

【3】patch()

* 特定のクラスやメソッドをモックで置き換えたい場合に使用

1)サンプル

test_demo_class.py

import unittest
from unittest.mock import patch, MagicMock
from demo_class import DemoClass

class TestDemoClass(unittest.TestCase):

  # テストメソッドを実行するたびに呼ばれる
  def setUp(self):
    print('setUp')
    self.target_class = DemoClass()
    # ★モッククラスを生成★
    self.mock = MagicMock()
    self.mock.return_value = 'Good evening from mock!!'

  # 3) say_thank_you
  def test_say_thank_you(self):
   # ★ここで、モックしている★
    with patch('demo_class.DemoClass.say_thank_you', self.mock):
      self.assertEqual(
        self.target_class.say_thank_you(),
        'Good evening from mock!!')

if __name__ == '__main__':
  unittest.main()

【4】サンプル

例1:例外を発生させるモック

import unittest
from unittest.mock import patch, MagicMock
from demo_class import DemoClass

class TestDemoClass(unittest.TestCase):

  # テストメソッドを実行するたびに呼ばれる
  def setUp(self):
    print('setUp')
    self.target_class = DemoClass()

  # 1) say_hello
  # ★ここに注目★
  @patch('demo_class.DemoClass.say_hello', MagicMock(side_effect=Exception('Mock Exception')))
  def test_say_hello(self):
    with self.assertRaises(Exception):
      self.target_class.say_hello()

if __name__ == '__main__':
  unittest.main()

参考文献

https://qiita.com/jansnap/items/570390197c3e52ee227c
https://qiita.com/sekitaka_1214/items/7bb19f554ceb5ce6b138

関連記事

単体試験 / unittest ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2019/10/02/223658
単体試験 / unittest ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2021/03/31/000000
単体試験 / unittest ~ あれこれ編 ~
https://dk521123.hatenablog.com/entry/2022/07/30/154233
単体試験 / mox ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/01/19/000000
単体試験 / nose ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/01/20/221014
単体試験 / pytest ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/12/13/224810