mercredi 28 janvier 2015

Problems trying to mock a Model within Flask-SQLAlchemy

I'm testing a Flask application that have some SQLAlchemy models using Flask-SQLAlchemy and I'm having some problems trying to mock a few models to some methods that receive some models as parameters.


A toy version of what I'm trying to do is like this. Suppose I have a model given by:



// file: database.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
birthday = db.Column(db.Date)


That is imported in an app that is built with the app factory pattern:



// file: app.py
from flask import Flask
from database import db

def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db.init_app(app)


And some function that needs a User as parameter:



// file: actions.py
import datetime

SECONDS_IN_A_YEAR = 31556926

def get_user_age(user):
return (datetime.date.today() - user.birthday).total_seconds() // SECONDS_IN_A_YEAR


Moreover there should be a couple of views and blueprints that are imported in app.py and registered in the app that latter call the function get_user_age somewhere.


My problem is: I want to test the function get_user_age without having to create an app, registering with a fake database, etc, etc. That shouldn't be necessary, the function is totally independent from the fact that it is used in a Flask app.


So I tried:



import unittest

import datetime
import mock

from database import User
from actions import get_user_age

class TestModels(unittest.TestCase):
def test_get_user_age(self):
user = mock.create_autospec(User, instance=True)
user.birthday = datetime.date(year=1987, month=12, day=1)
print get_user_age(user)


That raises me a RuntimeError: application not registered on db instance and no application bound to current context exception. So I thought "yeah, obviously I must patch some object to prevent it from checking if the app is registered with the database and etc". So I tried decorating it with @mock.patch("database.SQLAlchemy") and other things to no avail.


Do anyone know what should I patch to prevent this behavior, or even if my test strategy is all wrong?


Aucun commentaire:

Enregistrer un commentaire