Python 3.3 から標準で unittest.mock が使えるそうです。Python 3.2 の場合 PyPI から取ってきます。
import sys
assert(sys.version_info[0] == 3)
if sys.version_info[1] >= 3:
from unittest import mock
else:
import mock
使い方については本家 (http://docs.python.org/dev/library/unittest.mock) が詳しいのであまり書きませんが、個人的に便利そうだったのは mock.patch です。
(mockをいんぽーと)
>>> from StringIO import StringIO
>>> def foo():
... print 'Something'
...
>>> @mock.patch('sys.stdout', new_callable=StringIO)
... def test(mock_stdout):
... foo()
... assert mock_stdout.getvalue() == 'Something\n'
...
>>> test()
モックアウトのためにわざわざ引数増やしてたりしたんですが、そんな必要はなかったのですねぇ……
で、今実験的に使ってみてハマった件がひとつあるので、(上のページに書いてありますが) 一応言及しておきます (26.4.3.8. Where to patch)
a.py
-> Defines SomeClass
b.py
-> from a import SomeClass
-> some_function instantiates SomeClass
この状況で SomeClass をモックアウトして some_function をテストしたいとします。まぁよくありますよね。別にSomeClassではなくて別の関数でも良いです。
この場合、
@mock.patch('b.SomeClass')
が正しいのです。 'a.SomeClass' ではない。
b.py が "from a import SomeClass" をやった時点で b は本物の SomeClass への正しい参照を確保してしまいます。 a.SomeClass が参照する先を mock.patch で書き換えても意味はないのだそうです (詳しくは、上を読め)。
微妙に異なる以下のシナリオが考えられます。
a.py
-> Defines SomeClass
b.py
-> import a
-> some_function instantiates a.SomeClass
この場合、
@mock.patch('a.SomeClass')
が正しいそうです。紛らわしいやっちゃ。
まぁどちらにしても、標準ライブラリの範囲にこういう機能があるのは良いなぁ、と思いました。あくまで Python 3.3 ですが