mockを使用してpythonアプリケーションをテストする


最近nosetestsとmock 1をbottleに適用してテストしたところ、nosetestsを使用する上で注意すべき点がいくつか見つかりました.
1 patch method of module
patchはmoduleをインポートするmethodである、methodはすでにターゲットファイルにインポートされているため、元のmoduleではなくpatchターゲットファイルのこの方法が必要である.
# wsgi.py
from db import get_db

def insert_something():
    get_db().insert(something)

# test.py
import wsgi

# @patch('db.get_db') # this won't work
@patch('wsgi.get_db') # should patch wsgi
def test_insert(mock_get_db):
    mock_get_db.return_value = Database()
    ...

2 patch decorator
Scenario:bottleのviewsはdecoratorで定義されています.つまり、bottleのactionをテストするとき、このactionはviewsに包まれています.returnのdictはbottleのviews関数renderによってhtmlに戻されます.viewsが返すhtmlをテストする必要はありません.returnのdictが正しいかどうかをテストするだけです.
この状況はmockのpatchにぴったりだ.
  • patch bottle.view
  • は、神馬がやっていない関数
  • を返します.
  • このpatch
  • を起動
  • テストが必要なアプリケーションコード
  • をインポート
    ここのpatchはimportあなたのアプリケーションの前になければなりません.例えば、私のアプリケーションはwsgi.pyです.
    完全なプロセスはこうです
    from mock import patch, Mock
    import bottle
    v = patch("bottle.view",return_value = lambda x : x)
    v.start() **    local config        
    import wsgi
    

    3 mock module that may not exist
    Scenario:いくつかのスプーン付きプロファイル(google api keyなど)はgithub publicにアップロードされることを望んでいませんが、テストにはこれらのファイルを導入する必要があります.(後に、local configを使用してスプーンを保存するよりelegantの解決策を発見しました).スプーン付きプロファイルをconfig.pyと仮定すると、ターゲットファイルはwsgi.pyです.
    これではpatchでは何の役にも立たない.patchの場合、まずターゲットファイルを導入しなければならないので、ターゲットファイルのimport configが先に異常を投げ出すからだ.
    では、wsgiを導入する前にpatch configについて、システムのconfigモジュールをmockのconfigに等しくする必要があります.これでwsgiを導入しても問題はありません.
    import sys
    config_mock = Mock(spec=['config'])
    config_mock.__name__ = 'config'
    sys.modules['config'] = config_mock
    

    4 travis ciによる継続的な統合
    継続的な統合の最も簡単な構成はもちろんTravis CIです.構成ファイル.travis.ymlを追加するだけで、4つのものを定義するだけです.次は私の.travis.ymlです.
    language: python
    python:
      - "2.7" # version
    
    install: "pip install -r requirements.txt --use-mirrors"  # requirements
    
    script: nosetests  # test or build command
    

    5 local configを使用してスプーンを保存
    この方法はdjango.から突然djangoのsettings.pyの最後の数行を思い出した.
    try:
        from local_settings import *
    except:
        pass
    
    local_settingsのすべての設定から導入することを意味するので、本物のスプーン付き本物の配置をlocal_settingsに書くことができる.
    Footnotes:
    1
    : mock is now part of the python 3 now. Whee…..
    [](http://oyanglul.us/#/gist/9866674/How to use Mock testing Python)