Pythonでテスト  mock.patchの具体的な使い方

Python学習【365日チャレンジ!】198日目のマスターU(@Udemy11)です。

198という数字で思い浮かべるのはなんと言っても

「イチキュッパ」

昭和生まれの人ならわかると思いますが、平成生まれの人には、???となるかもしれません。

物販のコマーシャルでの決め台詞で、「今ならなんとイチキュッパ」なんてフレーズがよく使われていました。

一部のCMでは今でも使っているところがあるかもしれませんが、値段が19,800円か1,980円の商品のことで、キリのいい20,000円や2,000円よりもお得感が感じられる価格設定だそうです。

19,900円や1,990円だとだめみたいですよ。

このあたりの人間心理を学んでみるのもおもしろいかもしれませんね。

それでは、今日もPython学習をはじめましょう。

昨日の復習

昨日は、デコレーターを使ってmock.patchを使う方法を学習しました。

mock.patchを使えばMagicMockを使わなくてもmockのメソッドが呼び出されているかテストをすることができました。

デコレーターを使ったmock.patchのテストについては、こちらの記事をごらんください。

今日は、デコレーターを使わずにmock.patchを使う方法を学習します。

salary.py

メインのファイル(salary.py)は昨日と同じで、外部サービスからボーナスの額を取得して、毎月の給料と合わせた金額を出すコードになります。

昨日の記事のsalary.pyを参考にしてみてください。

withステートメント

デコレーターを使わずにmock.patchを利用するにはwithステートメントを使います。

import unittest
from unittest import mock

import salary


class TestSalary(unittest.TestCase):
    def test_cal_salary_patch_with(self):
        with mock.patch('salary.BonusApi.bonus_price') as mock_bonus:
            mock_bonus.return_value = 100

            s = salary.Salary(year=2020)
            salary_price = s.cal_salary()

            self.assertEqual(salary_price, 150)
            mock_bonus.assert_called()

テスト関数名はtest_cal_salary_patch_withにして、9行目でwithステートメントでmock.patchを開いています。

デコレーターで記述していた部分がまるごとwithステートメントに差し替えたような感じですね。

デコレーターを使えば、テストの関数がまるごとmockとして扱われてしまいますが、withステートメントを使えば、テスト関数の中でmockで扱う部分とそれ以外の部分を使い分けることができます。

patcher

もう一つ、デコレーターを使わずにmock.patchを使う方法を学習しましょう。

    def test_cal_salary_patcher(self):
        patcher = mock.patch('salary.BonusApi.bonus_price')
        mock_bonus = patcher.start()
        mock_bonus.return_value = 100

        s = salary.Salary(year=2020)
        salary_price = s.cal_salary()

        self.assertEqual(salary_price, 150)
        mock_bonus.assert_called()
        patcher.stop()

8行目からの記述にしていますが、テスト関数の名前をpatcherに変更しています。

9行目でmockpatcherを定義して、10行目でpatcherをスタートします。

テストコードを実行したあとは、最後にpatcherをストップします。

setupとteardown

patcherを使う場合は、スタートとストップが必要なので、具体的な使用方法としては、setupteardownを使います。

    def setUp(self):
        self.patcher = mock.patch('salary.BonusApi.bonus_price')
        self.mock_bonus = self.patcher.start()

    def tearDown(self):
        self.patcher.stop()

    def test_cal_salary_patcher(self):
        self.mock_bonus.return_value = 100

        s = salary.Salary(year=2020)
        salary_price = s.cal_salary()

        self.assertEqual(salary_price, 150)
        self.mock_bonus.assert_called()

テストの前後の処理ができるsetUptearDownを使うことで、クラスオブジェクト内で、patchermock_bonusをいつでも呼び出せるようになります。

withステートメントを使って書いていたコードの変数にself.をつけて、あとに記述する関数で使えるようになるので、ある意味__init__の初期化処理みたいなものですね。

イメージが重要

現在、シリコンバレーで活躍する酒井さんの学習しつつ、健忘録的にこのPython学習365日チャレンジを継続しています。

Udemy講師 酒井さん プログラミング Python

酒井さんの講座は、290レクチャーで総時間が28時間を超える内容の濃いものですが、ただ観るだけではPythonをマスターすることはできません。

私自身、初めて見るレクチャーの場合は、1回目で内容を理解することができません。

実際に自分で同じコードを書きつつ、疑問に感じたことをネットで調べ、さらにこのサイトで記事にすることで、記憶の定着を図ろうとしています。

わからないながらも、どんな場面でどのように使うのかをしっかりとイメージして学習しなければ、ただのテクニックとして記憶の片隅に残るだけですので、しっかりと使い所をイメージしつつ学習するようにしましょう。

それでは明日も、Good Python!