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

后端 未结 2 1312
爱一瞬间的悲伤
爱一瞬间的悲伤 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')
    ...
    <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'>
    
    0 讨论(0)
  • 2020-12-30 06:07

    Just a sum-up from Martijn Pieters answer

    Target

    • We want to mock .query.filter_by().all() result e.g. SomeModel.query.filter_by().all()

    Code 01

    @patch('flask_sqlalchemy._QueryProperty.__get__')
    def test (
      self,
      queryMOCK,
    ):
    
      #setup
      queryMOCK\
        .return_value.filter_by\
        .return_value.all\
        .return_value = [1,22] #empty list of current product_id
    
      #get actual
      modelObj = SomeModel.query.filter_by().all()
      print(modelObj)
    

    Code 02 - similar as above and using with

    def test(self):
      with patch('flask_sqlalchemy._QueryProperty.__get__') as queryMOCK      #setup
        queryMOCK\
          .return_value.filter_by\
          .return_value.all\
          .return_value = [1,22] #empty list of current product_id
    
        #get actual
        modelObj = SomeModel.query.filter_by().all()
        print(modelObj)
    
    0 讨论(0)
提交回复
热议问题