まだ作ってないクラスのモックを作りたい
とりあえず制御側を作りたいときにモデル作成を後回しにできます。
test_login.py
import unittest
class TestLoginMethod(unittest.TestCase)
def test_login_returns_true(self):
m = mox.Mox()
user = m.CreateMockAnything() # 将来作るUserモデルクラスのつもり
user.account().AndReturn("norobust") # アカウント名をとりあえず返す
l = Login() # これから開発するLoginクラス
l.user = user # Login クラス内から参照できるようモックを渡す
m.ReplayAll() # mox 始動!
self.assertTrue(l.login()) # ログインテスト!
m.VerifyAll() # mox 結果チェック!
mox で VerifyAll することで、セットアップしたメソッド(ここではuser.account())が呼ばれたかどうかをチェックします。
すでに存在するクラスのモックを作りたい
上のテストが終わって、Userクラスが出来上がったなら、CreateMockAnything をやめて、
m.CreateMock(User) にするだけです。
メソッドを置き換えてダミーのデータ(モック)を渡したい
上の場合、l.user = user
という具合ですが、実際には Login.login() 内部で self.user = get_user_by_id(1)
みたいなことを書いてユーザモデルを得ることになるかと思います。get_user_by_id が本当にコールされてしまうと、作った User モックを渡せません。この場合は、Login クラスのモックを作るのではなく、get_user_by_id() のみをスタブ化すればOKです。
test_login.py
import unittest
class TestLoginMethod(unittest.TestCase)
def test_login_returns_true(self):
m = mox.Mox()
user = m.CreateMockAnything() # Userモデルまだ作ってない・・・
user.account().AndReturn("norobust") # アカウント名をとりあえず返す
l = Login() # これから開発するLoginクラス
m.StubOutWithMock(Login, 'get_user_by_id') # スタブ化
Login.get_user_by_id().AndReturn(user) # スタブ化した関数の戻り値をセット
m.ReplayAll() # mox 始動!
self.assertTrue(l.login()) # ログインテスト!
m.VerifyAll() # mox 結果チェック!
注意すること
- CreateMockAnything は、__存在しないクラスのモック__を作る。よって AndReturn などで戻り値を偽装するメソッドも存在しない
- CreateMock は、__存在するクラスのモック__を作る。よって、クラスも偽装するメソッドも実際にコードを書いてからモックにする
- StubOutWithMock も存在するクラスとメソッドでないとスタブ化できない
- 偽装したメソッドは、実装コードの中でコールされないと VerifyAll でエラーになる
まとめ
- CreateMockAnything は、コードの書き始めなど、おおまかな実装コードを書くのに向いてます
- CreateMockAnything が嫌になってくるので、CreateMock によるテストを追加します
- CreateMock だと実際にクラスを書く必要があるので、必要なクラスを書きます
- さらに細かく実装を積み重ねるべく StubOutWithMock して完成を目指す
- 気がついたら完成している( ̄ー ̄)ニヤリ