最近在用 nosetests 和 mock1 为 bottle 应用测试, 发现几个使用nosetests 要注意的 地方: python
1 patch method of module
patch 一个导入 module 的 method, 由于 method 已经被导入到目标文件, 所以必须 要 patch 目标文件的 该方法, 而不是原 module. git
# 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 是否正确. github
这种状况太适合 mock 的 patch 来干了. django
- patch bottle.view
- 让其返回一个神马都没干的函数
- 启动这个patch
- 导入须要测试的应用代码
注意 这里的patch必须在 import 你的 application 以前, 好比个人应用是 wsgi.py
api
完整过程是这样的 markdown
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 上, 可是测试又须要引入这些文件.(后来我发现了更 elegant 的解决方式 使用 local config 来存放你的密匙). 假设如今含密匙的配置文件叫 config.py, 目标文件是 wsgi.py app
这样的话用 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…..