4
4

More than 5 years have passed since last update.

unittest.mock

Last updated at Posted at 2013-07-31

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 ですが

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4