简体   繁体   中英

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM