Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Python mock to spy on calls to an existing object

I'm using the Python mock module for tests. I would like to replace an active object with a mock, and automatically have all calls made to the mock object forwarded to the original object. I think this is called a "Spy" in standard testing terminology. At the moment I'm doing inside a test:

# Insert a mock replacement orig_active_attr = server.active_attr server.active_attr = mock.Mock()  # Set up side effects to 'proxy' to the original object server.active_attr.meth1.side_effect = orig_active_attr.meth1 server.active_attr.meth2.side_effect = orig_active_attr.meth2  # Call the method being tested server.method_being_tested()  # Assert stuff on the mock. server.active_attr.meth2.assert_called_once() 

It would be nice if all method calls on the mock could be forwarded to the live object automatically without the boilerplate.

like image 885
NeilenMarais Avatar asked Sep 18 '13 09:09

NeilenMarais


People also ask

How do you mock method calls 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 the difference between mock and MagicMock?

Mock vs. So what is the difference between them? MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.

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.


2 Answers

I seem to have stumbled across the solution:

import mock  class A(object):     def meth(self, a):         return a a = A() ma = mock.Mock(wraps=a) 

Seems to work okay for functions, methods and properties, but not for class or instance attributes.

See the documentation.

like image 115
NeilenMarais Avatar answered Sep 20 '22 13:09

NeilenMarais


You can use patch.object(wraps=obj_instance) as suggested in Spying on instance methods with Python's mock module.

For example:

from mock import patch  class Foo(object):     def bar(self, x, y):         return x + y + 1  def test_bar():     foo = Foo()     with patch.object(foo, 'bar', wraps=foo.bar) as wrapped_foo:         foo.bar(1, 2)         wrapped_foo.assert_called_with(1, 2) 
like image 32
Wilfred Hughes Avatar answered Sep 23 '22 13:09

Wilfred Hughes