📑

Pythonのmock触ってみた

2021/02/20に公開

はじめに

これはPythonしょしんしゃによるmock触ってみた系の備忘録です。

mockとは?

mockとはあるオブジェクトを擬似的なオブジェクトに設定するものです。
テストの実装時によく使われます。

例えば

  • テスト実行時に毎回DBに接続したくない
  • テスト実行時に外部APIに接続したくない

といった場合に、そのDBやAPIに接続する処理を擬似的なオブジェクト(mockオブジェクト)に置き換えることで毎回アクセスすることなく、テストを実行することができるようになります。

実際に使ってみる

以下のようなコードがあったとします。

class Dog:
    """
    犬
    """
    def __init__(self):
        """
        dogの鳴き声を設定
        """
        self.greet = "bow!"

    def hello(self):
        """
        犬があいさつする時の鳴き声を返す
        """
        return self.greet


class Owner:
    """
    飼い主
    """
    def __init__(self, dog):
        """
        飼い主は犬を一匹飼う
        """
        self.dog = dog

    def order(self):
        """
        犬にあいさつさせる
        """
        print(self.dog.hello())


if __name__ == '__main__':
    dog = Dog()
    owner = Owner(dog=dog)

    owner.order()

実際に実行した時の結果は以下です。

bow!

ここで「Ownerがorderを実行するとDogに設定されている値を一回出力する」というテストがしたいという要件があったとします。

コードはOwnerがDogの実装に依存している状態です。
ここからOwner単体が目的の動作をしているかテストしたい場合にどうするか。
このような場合にmockを使います。

class Dog:
    def __init__(self):
        self.greet = "bow!"

    def hello(self):
        return self.greet


class Owner:
    def __init__(self, dog):
        self.dog = dog

    def order(self):
        # dogの機能を使っているので、dogに依存している
        print(self.dog.hello())

Dogオブジェクトをmockにします。

if __name__ == '__main__':
    # Dogのmockオブジェクトを生成
    dog = Mock(spec=Dog)
    # Dog.hello()の返り値を変更
    dog.hello.return_value = "ワンワン!"

    owner = Owner(dog=dog)
    owner.order()

    # 呼び出し回数を表示
    print(dog.hello.call_count)

実際に実行してみます。

ワンワン!
1

Dogに指定されている値が一回実行されていることが確認できます。
これで実際のDogの挙動に依存することなく、Ownerのorderの挙動をテストすることができました。
mock素敵。

おわりに

mockには

  • 処理結果を書き換える
  • 呼び出し回数を計測する
  • 例外を発生させる

などの様々な機能があります。

とても便利なので、有効なタイミングがあればどんどん使っていきたいですね。

Discussion