lrpri ya
lrpri ya

Reputation: 73

Mock same method with different return value called twice in a function in python

I have a method to be tested using pytest. The method is calling same database model twice.

 def function:
    ids = database_model.object.filter(user="user1").filter(group="admin").values_list(ids, flat=True).allow_filtering()
    response_list = []
    unquie_ids = list(set(ids))
    for ids in unique_ids:
        response = database_model.object.filter(ids=ids).limit(1)
        for res in response:
            temp_dict = {}
            temp_dict['name'] = res.name
            temp_dict['description'] = res.description
            response_list.append(temp_dict)
   return response_list

This works well. I am tring to write unit test case for this. As the same database_model requires return value twice. It does not work for me.

  @patch('database_model')
  def test_function(mock_model):
      mock_model.objects.filter.return_value.filter.return_value.values_list.return_value.allow_filtering_return_value = [Mock_id]
      mock_model.objects.filter.limit.return_value = mock_dict

      response = function()

      assert len(response) > 0

mock_id and mock_dict are values created for test case. My question is first time i am assigning a return_value to mock_model.objects.filter.return_value.filter.return_value.values_list.return_value.allow_filtering.return_value to [Mock_id] which gets assigned properly. But the next line i am trying to assign a return_value again to the same method. This takes as a magic mock object. So my test case fails because it is getting a empty list. I would like to know how can i assign two different return_values to the same method.

Upvotes: 3

Views: 8050

Answers (1)

Michele d'Amico
Michele d'Amico

Reputation: 23711

You should write a side_effect for database_model.object.filter mock that gives you a Mock() configured to return the correct ids list after a mock to use in for cycle.

mock_filter_get_ids = Mock()
mock_filter_ids = Mock()
mock_model.objects.filter.side_effect = [mock_filter_get_ids, mock_filter_ids]
mock_filter_get_ids.filter.return_value.values_list.return_value.allow_filtering_return_value = [Mock_id]
mock_filter_ids.limit.return_value = mock_dict

But...

Forget it: refactor your code, at least extract:

database_model.object.filter(user="user1").filter(group="admin").values_list(ids, flat=True).allow_filtering()

In something like get_user_ids() and

database_model.object.filter(ids=ids).limit(1)

in get_ids_response().

You can mock the new methods and make your code simpler to read, simple to test means simple to read almost every time.

Upvotes: 2

Related Questions