How to mock nested / multiple layers of return objects in python -
i'm struggling find way of mocking multiple layers / nested return values. in other words, want return magic mock in turn returns magic mock it's own set return values. i'm finding relatively cumbersome , looking more elegant , maintainable solution.
i'm trying test following code efficiently. url returns json string needs further processing:
import json urllib.request import url open def load_json(): # first return value response = urlopen("http://someurl.com/api/getjson") # in turn, contains 2 nested return values read , decode response_dict = json.loads(response.read().decode('utf-8'))
this how i've mocked far, extremely inelegant , makes maintenance complicated:
class mytestcase(testcase): @patch('load_json_path.urlopen') def test_load_json(self, mock_urlopen): ### trying simplify of # third nested return mock_decode = magicmock(return_value='["myjsondata"]') # second nested return value mock_response = magicmock() mock_response.read.return_value=mock_decode # first nested return value mock_urlopen.return_value = mock_response ### trying simplify of load_json()
in end, i'm trying mock returned data decode function, originates url open function. should possible in 1 line or in simpler way, using perhaps enter methods. ideally mock in test_load_json function:
mock_urlopen.__enter__.loads.__enter__.decode.return_value = '["myjsondata"]'
unfortunately, can't seem find useful in mock documentation. appreciated.
turns out possible , documented. however, naming not straightforward , needed know 1 looking for. referred mocking chained calls, in fact documented in mock library.
in example, mock_urlopen should this:
mock_urlopen.return_value.read.return_value.decode.return_value = '["myjsondata"]'
this works beautifully. more details check out python doc: https://docs.python.org/3/library/unittest.mock-examples.html#mocking-chained-calls
Comments
Post a Comment