問(wèn)題描述
在Flask-SqlAlchemy中測(cè)試模型類時(shí),如何mock方法.query.filter_by()
以返回mocked模型對(duì)象列表?
When testing a model class in Flask-SqlAlchemy, how can we mock the method .query.filter_by()
so as to return the list of mocked model objects?
假設(shè)我們有一個(gè)模型類,如下代碼
Let's say we have a model class as below code
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class SomeModel(db.Model):
# more column mapping and methods go here
然后在我們的 Flask 代碼中調(diào)用
Then in our Flask code we call
SomeModel.query.filter_by(...)
在我們的測(cè)試代碼中,使用 Python unittest 模型和 mocking,我們要模擬 filter_by()
調(diào)用,以便它返回我們?cè)O(shè)計(jì)的測(cè)試用例下的模型對(duì)象列表.
In our testing code, using Python unittest model with mocking, we want to mock the filter_by()
call so that it returns a list of model objects under our designed test case.
我們?cè)鯓硬拍茏龅竭@一點(diǎn)?
How can we get to that?
附言
我的谷歌搜索只找到這篇相關(guān)帖子;雖然在課程開(kāi)始時(shí)應(yīng)用 @patch("flask_sqlalchemy.SignallingSession", autospec=True)
對(duì)我不起作用.
My google search only found this related post; though applying @patch("flask_sqlalchemy.SignallingSession", autospec=True)
at the beginning of the class not work for me.
我還嘗試將函數(shù)模擬如下代碼片段
I also tried to mock the function as below code snippet
@patch('app.model.some_model.SomeModel.query.filter_by')
def test_some_case(self, filterbyMOCK):
# more test logic goes here
并且代碼在啟動(dòng)時(shí)立即出錯(cuò)
and the code get immediate error when started
RuntimeError: application not registered on db instance and no application bound to current context
來(lái)自 PyCharm IDE 的完整錯(cuò)誤截圖如下.
The full error from PyCharm IDE as snapshot below.
Traceback (most recent call last):
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/mock/mock.py", line 1297, in patched
arg = patching.__enter__()
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/mock/mock.py", line 1353, in __enter__
self.target = self.getter()
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/mock/mock.py", line 1523, in <lambda>
getter = lambda: _importer(target)
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/mock/mock.py", line 1210, in _importer
thing = _dot_lookup(thing, comp, import_path)
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/mock/mock.py", line 1197, in _dot_lookup
return getattr(thing, comp)
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 428, in __get__
return type.query_class(mapper, session=self.sa.session())
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/sqlalchemy/orm/scoping.py", line 78, in __call__
return self.registry()
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/sqlalchemy/util/_collections.py", line 990, in __call__
return self.registry.setdefault(key, self.createfunc())
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 136, in __init__
self.app = db.get_app()
File "/home/namgivu/NN/code/someproject-cloud/venv/local/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 809, in get_app
raise RuntimeError('application not registered on db '
RuntimeError: application not registered on db instance and no application bound to current context
推薦答案
你必須模擬整個(gè)映射器類;訪問(wèn)映射器上的 query
屬性會(huì)導(dǎo)致會(huì)話加載:
You'll have to mock the whole mapper class; accessing the query
attribute on the mapper causes a session load:
@patch('app.model.some_model.SomeModel')
def test_some_case(self, some_model_mock):
filter_by_mock = some_model_mock.query.filter_by
# more test logic goes here
那是因?yàn)?.query
屬性是一個(gè)描述符對(duì)象;訪問(wèn)它會(huì)觸發(fā)與會(huì)話的綁定.
That's because the .query
attribute is a descriptor object; accessing it triggers the binding to a session.
替代方法是模擬 _QueryProperty.__get__
方法(支持 .query
屬性);僅當(dāng)您必須使用實(shí)際的 SomeModel
實(shí)例進(jìn)行測(cè)試時(shí)才使用它:
The alternative would be to mock out the _QueryProperty.__get__
method (which backs the .query
attribute); only use this if you must test with actual SomeModel
instances:
@patch('flask_sqlalchemy._QueryProperty.__get__')
def test_some_case(self, query_property_getter_mock):
filter_by_mock = query_property_getter_mock.return_value.filter_by
# more test logic goes here
演示:
>>> from flask_sqlalchemy import SQLAlchemy
>>> db = SQLAlchemy()
>>> class SomeModel(db.Model):
... id = db.Column(db.Integer, primary_key=True)
...
>>> from unittest import mock
>>> with mock.patch('__main__.SomeModel') as model_mock:
... filter_by = model_mock.query.filter_by
... SomeModel.query.filter_by(SomeModel.id == 'foo')
...
<MagicMock name='SomeModel.query.filter_by()' id='4438980312'>
>>> with mock.patch('flask_sqlalchemy._QueryProperty.__get__') as query_property_getter_mock:
... filter_by_mock = query_property_getter_mock.return_value.filter_by
... SomeModel.query.filter_by(SomeModel.id == 'foo')
...
<MagicMock name='__get__().filter_by()' id='4439035184'>
這篇關(guān)于如何在 Flask-SqlAlchemy 中模擬 <ModelClass>.query.filter_by()的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!