Flask-Injector を使ってモックに差し替える
Injector を使って DI してるんだから、テストコードからも置き換えたいよねーってお話。
# Mock を使って差し替える事も出来る
app.py
# -*- coding: utf-8 -*- from flask import Flask from flask.ext.injector import init_app, post_init_app from binds import configure from views.index import app as index_view def create_app(binds=None): app = Flask(__name__) app.register_blueprint(index_view) if binds is None: binds = configure injector = init_app(app=app, modules=[binds]) post_init_app(app, injector) return app def main(): app = create_app() app.debug = True app.run() if __name__ == '__main__': main()
binds.py
# -*- coding: utf-8 -*- from injector import inject, Key, singleton from flask import Flask from flask.ext.injector import request from models.localfs import LocalFS as LocalFSProvider from models.riakcs import RiakCS as RiakCSProvider FileStorage= Key('filestorage') RiakCSStorage = Key('riakcsstorage') @inject(app=Flask) def configure(binder, app): binder.bind(FileStorage, to=LocalFSProvider(app.config), scope=singleton) binder.bind(RiakCSStorage, to=RiakCSProvider, scope=request)
view/index.py
# -*- coding: utf-8 -*- from injector import inject from flask import Blueprint from binds import FileStorage, RiakCSStorage app = Blueprint('index', __name__) @app.route('/', strict_slashes=False, methods=['GET']) @inject(service=FileStorage) def index(service): print(service) return service.save() @app.route('/<key>', strict_slashes=False, methods=['GET']) @inject(service=RiakCSStorage) def get_key(key, service): print(service) return service.save()
テストコード。
binds をテストコードで使うのに置き換える。
create_app() で引数で configure オブジェクトを渡し、create_app() 内の init_app() のを差し替える。
ただし、Key() で定義したものは元のを使う。
tests.py
# -*- coding: utf-8 -*- from unittest import TestCase from injector import inject, singleton from flask import Flask from flask.ext.injector import request from app import create_app from binds import FileStorage, RiakCSStorage from models.base import Base @inject(app=Flask) def configure(binder, app): binder.bind(FileStorage, to=MockStorage, scope=singleton) binder.bind(RiakCSStorage, to=MockStorage, scope=request) class MockStorage(Base): def save(self): return 'mock' class Tests(TestCase): def setUp(self): self.app = create_app(binds=configure) self.client = self.app.test_client() def test_view_index(self): with self.client as c: ret = c.get('/') print(ret) if __name__ == '__main__': import unittest unittest.main()
実行してみる。
$ python tests.py <__main__.MockStorage object at 0x102ac4710>
ちゃんと MockStorage に置き換わった。