Setu Kumar Basak
Setu Kumar Basak

Reputation: 12022

How to mock chained calls in pytest-mock

I am trying to use pytest-mock to mock chained function calls.

@app.route('/application', methods=['PUT'])
    def update_application():
        a = json.loads(request.data)['application']
        application = Application.objects(id=a['id']).first()
        if not application:
            return jsonify({'error': 'data not found'})
        else:
            application.update(jobTitle=a['jobTitle'],
                                companyName=a['companyName'],
                                date=a['date'],
                                status=a['status'

The method update_application has a chained function call like below

Application.objects(id=a['id']).first()

I have tried mocking the chained calls using below approach but I could not mock.

def test_update_application(client, mocker):
    application = Application(id=4, jobTitle='fakeJob12345', companyName='fakeCompany', date=str(datetime.date(2021, 9, 22)))
    mocker.patch(
        'app.Application.update'
    )
    m = mocker.MagicMock()
    m.Application.objects().first.return_value = application
    rv = client.put('/application', json={'application':{
        'id':2, 'jobTitle':'fakeJob12345', 'companyName':'fakeCompany', 'date':str(datetime.date(2021, 9, 23)), 'status':'1'
        }})
    print(rv.data)
    jdata = json.loads(rv.data.decode("utf-8"))["jobTitle"]
    assert jdata == 'fakeJob12345' 

I could mock Application.objects(id=a['id']) like below which worked fine.

mocker.patch(
        'app.Application.objects',
        return_value = list_application
    )

Can anyone point me on how to mock chained functions?

Upvotes: 0

Views: 1473

Answers (1)

Peter K
Peter K

Reputation: 2474

Here is how you could do this - I only changed the 3 code lines dealing with the mock:

def test_update_application(client, mocker):
    application = Application(id=4, jobTitle='fakeJob12345', companyName='fakeCompany', date=str(datetime.date(2021, 9, 22)))

    mock_objects = mocker.MagicMock(name='objects')
    mocker.patch('app.Application.objects', new=mock_objects)
    mock_objects.return_value.first.return_value = application

    rv = client.put('/application', json={'application':{
        'id':2, 'jobTitle':'fakeJob12345', 'companyName':'fakeCompany', 'date':str(datetime.date(2021, 9, 23)), 'status':'1'
        }})
    print(rv.data)
    jdata = json.loads(rv.data.decode("utf-8"))["jobTitle"]
    assert jdata == 'fakeJob12345'

It's important to understand that you are mocking the objects function of the Application class, like so: mocker.patch('app.Application.objects', new=mock_objects).

Then, you need to set the return value: mock_objects.return_value.first.return_value = application.

The first part mock_objects.return_value is matching the object returned in Application.objects(id=a['id']), then you need to append .first.return_value = application which matches the return value of .first()

Upvotes: 1

Related Questions