How to mock .query.filter_by() in Flask-SqlAlchemy

后端 未结 2 1315
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-30 05:45

In brief

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 object

2条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-30 06:02

    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
    

    That's because the .query attribute is a descriptor object; accessing it triggers the binding to a session.

    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
    

    Demo:

    >>> 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')
    ...
    
    >>> 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')
    ...
    
    

提交回复
热议问题