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 に置き換わった。