How to mock lt;ModelClassgt;.query.filter_by() in Flask-SqlAlchemy(如何在 Flask-SqlAlchemy 中模拟 lt;ModelClassgt;.query.filter_by())
问题描述
在Flask-SqlAlchemy中测试模型类时,如何mock方法.query.filter_by()以返回mocked模型对象列表?
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?
假设我们有一个模型类,如下代码
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 代码中调用
Then in our Flask code we call
SomeModel.query.filter_by(...)
在我们的测试代码中,使用 Python unittest 模型和 mocking,我们要模拟 filter_by() 调用,以便它返回我们设计的测试用例下的模型对象列表.
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.
我们怎样才能做到这一点?
How can we get to that?
附言
我的谷歌搜索只找到这篇相关帖子;虽然在课程开始时应用 @patch("flask_sqlalchemy.SignallingSession", autospec=True) 对我不起作用.
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.
我还尝试将函数模拟如下代码片段
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
并且代码在启动时立即出错
and the code get immediate error when started
RuntimeError: application not registered on db instance and no application bound to current context
来自 PyCharm IDE 的完整错误截图如下.
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
推荐答案
你必须模拟整个映射器类;访问映射器上的 query 属性会导致会话加载:
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
那是因为 .query 属性是一个描述符对象;访问它会触发与会话的绑定.
That's because the .query attribute is a descriptor object; accessing it triggers the binding to a session.
替代方法是模拟 _QueryProperty.__get__ 方法(支持 .query 属性);仅当您必须使用实际的 SomeModel 实例进行测试时才使用它:
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'>
这篇关于如何在 Flask-SqlAlchemy 中模拟 <ModelClass>.query.filter_by()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在 Flask-SqlAlchemy 中模拟 <ModelClass&g
- 计算测试数量的Python单元测试 2022-01-01
- 使用公司代理使Python3.x Slack(松弛客户端) 2022-01-01
- ";find_element_by_name(';name';)";和&QOOT;FIND_ELEMENT(BY NAME,';NAME';)";之间有什么区别? 2022-01-01
- CTR 中的 AES 如何用于 Python 和 PyCrypto? 2022-01-01
- 使用 Cython 将 Python 链接到共享库 2022-01-01
- 我如何卸载 PyTorch? 2022-01-01
- 我如何透明地重定向一个Python导入? 2022-01-01
- YouTube API v3 返回截断的观看记录 2022-01-01
- 检查具有纬度和经度的地理点是否在 shapefile 中 2022-01-01
- 如何使用PYSPARK从Spark获得批次行 2022-01-01
