Home > Net >  Pytest- mock chained call
Pytest- mock chained call

Time:02-23

I'm trying to mock chained call in pytest (and pytest-mock package), but for some unknown (for me) reason it doesn't work which means I don't get mocked return_value from my mock. It looks like it created object of MagicMock, but without defined return_value. My guess is that it's related to chained call.

class DatabaseService():
    def __init__(self):
        self.db = next(get_db())
        self.categories = {}

    def save(self, product_id):
        if not self.categories:
            self._load_existing_categories()
        ...
        [rest of the code]

    def _load_existing_categories(self):
        # result = self.db.execute(select(Category).order_by(Category.id)).all() <-- This is my original line, but I can't make it working even with simplified version (line below)
        result = self.db.execute().all()
        for obj in result:
            print("Result")
            print(obj)
            self.categories[obj.Category.name] = obj.Category

Here is my test:

def test_load_from_database(mocker):
    session = mocker.patch('src.mysql.get_db')

    session.execute.all.return_value = ['1st element', '2nd element']

    # I tried also mock it by these ways:
    # session = mocker.MagicMock()
    # session.session.execute().all().return_value = ['1st element', '2nd element']
    # session.get_db.execute().all().return_value = ['1st element', '2nd element']
    # session.execute.all = ['1st element', '2nd element']

    service = DatabaseService()
    service.save = mocker.MagicMock(side_effect=service.save)
    service.db = session

    service.save(123)
    
    [here will be some assert once I make it working]

For some reason, mock of self.db.execute().all() doesn't return anything. The code inside loop is not executed even single time.
When I print print(result) I get:

<MagicMock name='get_db.execute().all()' id='140427147903424'>

But it looks like return_value is not assigned to it, so either it's not the same object or value is removed somehow.

CodePudding user response:

Your code calls this:

self.db.execute().all()

In your test you are setting this:

session.execute.all.return_value

I think you should set:

session.execute.return_value.all.return_value

because your code calls execute, so you need to set up mocks on its return value.

  • Related