Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 431
lrpri ya Avatar asked Jan 18 '26 12:01

lrpri ya


1 Answers

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.

like image 182
Michele d'Amico Avatar answered Jan 21 '26 00:01

Michele d'Amico



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!