Python mockを使って仮想テスト

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

近所の方からスイカを一玉いただきました。

普段なら、普通に切って、皮が付いたままかぶりつくのですが、今回は趣向を変えて、フルーツミックスとしてスーパーで売っているような感じで一口サイズにカットしていただきました。

思った以上に食べやすくて、甘かったので、ついつい食べすぎて、お腹がパンパンになってしまいました。

スイカはほぼ水分なので、体重が増えてしまいましたが、明日になればもとに戻っているような気がします。

ほんとこの時期のスイカってめっちゃ美味しいですよね。

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

昨日の復習

昨日はUIテストができるseleniumを使ってPython.orgのWebページを操作してみました。

Webブラウザーを立ち上げて、検索窓に入力したり、その結果がどのようになるのかをテストしたりしました。

ユーザーが実際にWebページでマウスを操作するような動作をテストすることができるので、リモート操作をしているような感じでしたね。

具体的なseleniumの使い方については、昨日の記事を参考にしてください。

今日は、外部のAPIなどから帰ってくる値を擬似的に取得してテストを実行するmockを学習します。

mock

mockは、作成するコードの中に、外部のサービスを利用して値を取得してくるコードがある場合、擬似的に返される値を指定してテストを実行することができるオブジェクトライブラリです。

10年ほど前なら携帯ショップにおいていた実際には使えない見本の携帯がモックと言われていましたが、最近では、見本のスマホは普通に使えますよね。

mockは、【模造品】、【まがい物】という意味ですが、Pythonのmockも実際の処理をせずに返り値だけ模擬的に取得するという意味では、mockの意味そのままですね。

mockを使ったテストの簡単な具体例をみていきましょう。

salary.py

今回のメインファイルは、salary.pyとして、外部のサービスからボーナスの金額を取得して、月給と合わせた金額を計算するコードを書いています。

import requests

class BonusApi(object):
    def bonus_price(self, year):
        req = requests.get('http://localhost/bonus', params={'year': year})
        return req.json()['price']
    
class Salary(object):
    def __init__(self, base=50, year=2020):
        self.bonus_api = BonusApi()
        self.base = base
        self.year = year
        
    def cal_salary(self):
        bonus = self.bonus_api.bonus_price(year=self.year)
        return self.base + bonus

以前学習したrequestsをインポートして、3行目から6行目でhttp://localhost/bonusからjsonファイルのpriceを取得する関数を作成しています。

このときにサーバーから取得するjsonは、{'price': 100}というような値が入っているファイルを想定しています。

8行目からは、Salaryクラスを作成してBounusApiから取得した値とbaseyearをself変数に代入、14行目から16行目で代入した値を使って、basebonusをあわせた金額を返すcal_salaryのコードを記述しています。

test_salary.py

salary.pyをテストするのがtest_salary.pyです。

通常のテストなら、外部サービスにアクセスして値が返されているか確認しますが、サーバーがダウンしていたり、自社のサービスでまだ完成していないけれど取得できる情報が決まっているときなどにmockを使って仮の値を入れてテストすることができます。

それでは、テストコードを書いてみましょう。

import unittest

from unittest.mock import MagicMock

import salary


class TestSalary(unittest.TestCase):
    def test_cal_salary(self):
        s = salary.Salary()
        s.bonus_api.bonus_price = MagicMock(return_value=100)
        self.assertEqual(s.cal_salary(), 150)

単独のサードパーティーライブラリだと思っていたのですが、mockってunittestの一部だったんですね。

最初にunittestとMagicMock、salary.pyをインポートして、TestSalaryクラスを作成します。

11行目で本来外部サービスから取得するメインファイルのbonus.priceの値にMagicMockを使って100を代入して12行目で計算結果が150になるかどうかをテストしています。

実行結果

Python mockを使って仮想テスト

デバッグを使って実行してみると、外部サービスから取得する値のbonus_api.bonus_priceMagicMockで代入した100が入っているのがわかるかと思います。

APIを使いこなしたい

外部サービスから情報を取得するAPIはたくさんあるので、使いこなせるようになればかなりレベルアップすること間違いなしです。

仕組みをきっちりと理解して使いこなすためには、まだまだ時間がかかりそうですが、プログラムを学習する上で、避けて通れない道ですので、じっくり学んでいこうと思います。

今回学習したmockは、外部サービスを使ったプログラムには必要不可欠のテストなので、他の使い方も含めて明日から学習していきます。

それでは、明日もGood Python!