Python SQLAlchemy mocking

nejdetckenobi picture nejdetckenobi · May 31, 2018 · Viewed 14.9k times · Source

this is a method that I made chained DB query calls.

import math
def get_all_keys():
    db_session = DBSession()
    keys = db_session.query(SomeClass).all()

I should mock DBSession().query(SomeClass).all(). I tried some but nothing worked. Here are my trials.

@patch('app.modules.somemodule.DBSession')
def test_asd(self, DBSession):
    DBSession.execute.query.execute.all.return_value = [1, 2, 3]
    self.assertListEqual(DBSession.query('qwe').all(), [1, 2, 3])

In this attempt if I try to print DBSession() I get a MagicMock object which seems fine. But when I run pytest I got following error.

    self = <test_some_module.SomeModuleTests testMethod=test_asd>, DBSession = <MagicMock name='DBSession' id='140028663111976'>

    @patch('app.modules.somemodule.DBSession')
    def test_asd(self, DBSession):
        DBSession.execute.query.execute.all.return_value = [1, 2, 3]
        print(DBSession().query('qwe').all())
>       self.assertListEqual(DBSession.query('qwe').all(), [1, 2, 3])
E       AssertionError: First sequence is not a list: <MagicMock name='DBSession.query().all()' id='140028662649184'>

tests/test_some_module.py:21: AssertionError

Seems like I did something wrong while mocking. What is my mistake? I checked the documentation.

Answer

Ilja Everil&#228; picture Ilja Everilä · May 31, 2018

You're simply mocking the wrong thing, and asserting that the chain of calls should return an actual list with given items, not a magic mock object. Instead of execute, which would simply mock access to the attribute of the same name, you should be using the return_value, as you've done in the final step. Given the chain

DBSession().query(...).all()

you should be mocking

DBSession.return_value.query.return_value.all.return_value = [1, 2, 3]

On the other hand in test_asd() in the assertion you're doing

DBSession.query(...).all()

so

DBSession.query.return_value.all.return_value = [1, 2, 3]