2015.07.30   |   Python

Pythonの万能モック MagicMockと戯れる

導入

Python3.3以降なら標準で利用できます。それ未満の場合は pip install mockしてインストールをします。

準備: MacigMockを作る

from unittest.mock import MagicMock
# Python3.3未満の場合はこっち
from mock import MagicMock

# MagicMockインスタンス作成
m = MagicMock()

いろいろ生やす

# 好きに生やせる
m.hoge = 123

# チェーンする場合も一気に生やせる
m.fuga.piyo = "abc"

# 辞書もいける
m["spam"]["ham"] = "egg"

# こんなのも
m.a["b"].c["d"] = "e"

いろいろ呼ぶ

# 勝手に生やしたものを関数として呼び出すことも可能
# 呼び出すとMagicMockが返る
m.hogehoge()
#=> <MagicMock name='mock.hogehoge()' id='4400997600'>

# 返り値をカスタマイズ 
m.hogehoge.return_value = "Hello"
m.hogehoge()
#=> 'Hello'

# 任意の引数付きでも呼べる
m.fugafuga(1,2,3, test="test")
#=> <MagicMock name='mock.fugafuga()' id='4401005680'>

# どんな引数で呼ばれたかを調べる
args, kwargs = m.fugafuga.call_args
args
#=> (1, 2, 3)
kwargs
#=> {'test': 'test'}

演算

# こんなことしても怒られない
m + 3
#=> <MagicMock name='mock.__add__()' id='4401022120'>

# 逆パターン
3 + m
#=> <MagicMock name='mock.__radd__()' id='4401038560'>

# MagicMockが返ってきてるので、
# メソッドと同じように演算結果を書き換えてみる
m.__add__.return_value = 10
m.__add__.return_value = 8

# 確認
m + 3
#=> 10
3 + m
#=> 8 

引数に応じて返り値を変える

# デフォルト
m.add(3, 5)
#=> <MagicMock name='mock.add()' id='4401046808'>

# 処理を定義
def add(x, y):
    return x + y

# m.addの挙動を指定
m.add.side_effect = add
# 上書き完了
m.add(3, 5)
#=> 8

# こうも書ける
m.add.side_effect = lambda x, y: x+y

# こうやると1つの引数をそのまま返すので便利かも
m.xx.side_effect = lambda x: x
m.xx(1234)
#=> 1234

スライス

# これでもエラーにならない
m.array[0:3]
#=> <MagicMock name='mock.array.__getitem__()' id='40564152'>

# ふむ
m.array.__getitem__.side_effect = lambda x: [i for i in range(x.start, x.stop)]
m.array[4, 7]
#=> [4, 5, 6]

(WIP)

遊びつつまた後日追記してきます。