2015-01-28 12 views
5

Tôi đang thử nghiệm một ứng dụng Flask có một số mô hình SQLAlchemy sử dụng Flask-SQLAlchemy và tôi đang gặp một số vấn đề khi thử một vài mô hình. thông số.Các vấn đề cố gắng giả lập một Mô hình trong Flask-SQLAlchemy

Một phiên bản đồ chơi của những gì tôi đang cố gắng làm là như thế này. Giả sử tôi có một mô hình được cho bởi:

// 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) 

Đó được nhập khẩu trong một ứng dụng mà được xây dựng với mô hình nhà máy ứng dụng:

// 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) 

Và một số chức năng mà cần một User như tham số:

// 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 

Ngoài ra, cần có một vài chế độ xem và bản thiết kế được nhập trong app.py và được đăng ký trong ứng dụng mà sau này gọi hàm get_user_age ở đâu đó.

Vấn đề của tôi là: Tôi muốn kiểm tra chức năng get_user_age mà không phải tạo ứng dụng, đăng ký với cơ sở dữ liệu giả, v.v. Điều đó không cần thiết, chức năng hoàn toàn độc lập với thực tế là được sử dụng trong ứng dụng Flask.

Vì vậy, tôi đã cố gắng:

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) 

Đó tăng cho tôi một ngoại lệ RuntimeError: application not registered on db instance and no application bound to current context. Vì vậy, tôi nghĩ "yeah, rõ ràng tôi phải vá một số đối tượng để ngăn chặn nó kiểm tra nếu ứng dụng được đăng ký với cơ sở dữ liệu và vv". Vì vậy, tôi đã thử trang trí nó với @mock.patch("database.SQLAlchemy") và những thứ khác không có kết quả.

Có ai biết tôi nên vá gì để ngăn chặn hành vi này hoặc thậm chí nếu chiến lược kiểm tra của tôi là sai?

Trả lời

6

Vì vậy, tôi đã tìm thấy giải pháp sau khi đập đầu trên bàn phím trong vài giờ. Vấn đề có vẻ như sau (nếu có ai biết rõ hơn, hãy sửa tôi).

Khi tôi chạy mock.create_autospec(User), mô-đun giả cố gắng kiểm tra tất cả các thuộc tính của User để tạo thông số đầy đủ cho đối tượng Mock nó sẽ nhổ ra. Khi điều này xảy ra, nó sẽ cố gắng kiểm tra thuộc tính User.query, chỉ có thể được đánh giá khi bạn ở trong phạm vi của ứng dụng Flask.

Điều này xảy ra vì khi đánh giá User.query, một đối tượng được tạo cần phiên hợp lệ. Phiên này được tạo bởi phương thức create_scope_session trên lớp SQLAlchemy bên trong Flask-SQLAlchemy.

Phương pháp này khởi tạo một lớp được gọi là SignallingSession có phương thức __init__ gọi phương thức SQLAlchemy.get_app. Đây là phương pháp tăng số RuntimeError khi không có ứng dụng nào được đăng ký trong db.

Bằng cách vá phương thức SignallingSession, mọi thứ hoạt động tốt. Vì tôi không muốn tương tác với cơ sở dữ liệu, điều này là ok:

import unittest 
import datetime 

import mock 

from actions import age 


@mock.patch("flask_sqlalchemy.SignallingSession", autospec=True) 
class TestModels(unittest.TestCase): 

    def test_age(self, session): 
     import database 

     user = mock.create_autospec(database.User) 
     user.birthday = datetime.date(year=1987, month=12, day=1) 
     print age(user) 
Các vấn đề liên quan