Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using python's mock patch.object to change the return value of a method called within another method

Is it possible to mock a return value of a function called within another function I am trying to test? I would like the mocked method (which will be called in many methods I'm testing) to returned my specified variables each time it is called. For example:

class Foo:     def method_1():        results = uses_some_other_method()     def method_n():        results = uses_some_other_method() 

In the unit test, I would like to use mock to change the return value of uses_some_other_method() so that any time it is called in Foo, it will return what I defined in @patch.object(...)

like image 555
mdoc-2011 Avatar asked Aug 12 '13 15:08

mdoc-2011


People also ask

What is patch object in Python?

The library also provides a function, called patch() , which replaces the real objects in your code with Mock instances. You can use patch() as either a decorator or a context manager, giving you control over the scope in which the object will be mocked.

How do you mock a value in 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 Side_effect in mock Python?

side_effect: A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns DEFAULT , the return value of this function is used as the return value.


1 Answers

There are two ways you can do this; with patch and with patch.object

Patch assumes that you are not directly importing the object but that it is being used by the object you are testing as in the following

#foo.py def some_fn():     return 'some_fn'  class Foo(object):     def method_1(self):         return some_fn() 
#bar.py import foo class Bar(object):     def method_2(self):         tmp = foo.Foo()         return tmp.method_1() 
#test_case_1.py import bar from mock import patch  @patch('foo.some_fn') def test_bar(mock_some_fn):     mock_some_fn.return_value = 'test-val-1'     tmp = bar.Bar()     assert tmp.method_2() == 'test-val-1'     mock_some_fn.return_value = 'test-val-2'     assert tmp.method_2() == 'test-val-2' 

If you are directly importing the module to be tested, you can use patch.object as follows:

#test_case_2.py import foo from mock import patch  @patch.object(foo, 'some_fn') def test_foo(test_some_fn):     test_some_fn.return_value = 'test-val-1'     tmp = foo.Foo()     assert tmp.method_1() == 'test-val-1'     test_some_fn.return_value = 'test-val-2'     assert tmp.method_1() == 'test-val-2' 

In both cases some_fn will be 'un-mocked' after the test function is complete.

Edit: In order to mock multiple functions, just add more decorators to the function and add arguments to take in the extra parameters

@patch.object(foo, 'some_fn') @patch.object(foo, 'other_fn') def test_foo(test_other_fn, test_some_fn):     ... 

Note that the closer the decorator is to the function definition, the earlier it is in the parameter list.

like image 118
Silfheed Avatar answered Oct 20 '22 18:10

Silfheed