Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assert mocked function called with json string in python

Writing some unit tests in python and using MagicMock to mock out a method that accepts a JSON string as input. In my unit test, I want to assert that it is called with given arguments, however I run into issues with the assert statement, since the ordering of objects within the dict doesn't matter, besides in the assert statement for the string. Simplified example of what I am trying to achieve below.

mock_funct = MagicMock()
# mocked function called elsewhere
expected = {"a":"a", "b":"b"}
mock_funct.assert_called_once_with(json.dumps(expected))

The above may pass or may fail due to the arbitrary ordering of the keys within the dict when it is dumped to json, ie both '{"a":"a", "b":"b"}' and '{"b":"b", "a":"a"}' are valid dumps but one would fail and one would pass, however I would like to write the test so that either would pass.

like image 626
Brent Hronik Avatar asked Feb 09 '15 19:02

Brent Hronik


People also ask

How to mock a call to function Python?

How do we mock in Python? Mocking in Python is done by using patch to hijack an API function or object creation call. When patch intercepts a call, it returns a MagicMock object by default. By setting properties on the MagicMock object, you can mock the API call to return any value you want or raise an Exception .

What is @patch in Python?

This, along with its subclasses, will meet most Python mocking needs that you will face in your tests. The library also provides a function, called patch() , which replaces the real objects in your code with Mock instances.

What is JSON loads in Python?

loads() method can be used to parse a valid JSON string and convert it into a Python Dictionary. It is mainly used for deserializing native string, byte, or byte array which consists of JSON data into Python Dictionary. Syntax : json.loads(s)


1 Answers

Unfortunately, you'll need to do your own checking here. You can get the calls from the mock via it's call_args_list attribute (or, simply call_args in this case since you have already asserted that it is called only once). I'll assume you're using unittest in my example code -- but it should be easy enough to adapt for any testing framework ...

mock_funct.assert_called_once_with(mock.ANY)
call = mock_funct.call_args
call_args, call_kwargs = call  # calls are 2-tuples of (positional_args, keyword_args)
self.assertEqual(json.loads(call_args[0]), expected)

I've still used assert_called_once_with to make sure that the function was only called once with a single positional argument, but then I open up the call to look at that argument to check that it is correct.

like image 136
mgilson Avatar answered Sep 28 '22 10:09

mgilson