Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - Mocking chained function calls

Tags:

I have the following statement in one of the methods under unit test.

db_employees = self.db._session.query(Employee).filter(Employee.dept ==        new_employee.dept).all() 

I want db_employees to get mock list of employees. I tried to achieve this using:

 m = MagickMock()  m.return_value.filter().all().return_value = employees 

where employees is a list of employee object. But this did not work. When I try to print the value of any attribute, it has a mock value. This is how the code looks:

class Database(object):     def __init__(self, user=None, passwd=None, db="sqlite:////tmp/emp.db"):         try:             engine = create_engine(db)         except Exception:             raise ValueError("Database '%s' does not exist." % db)          def on_connect(conn, record):             conn.execute('pragma foreign_keys=ON')          if 'sqlite://' in db:             event.listen(engine, 'connect', on_connect)         Base.metadata.bind = engine         DBSession = sessionmaker(bind=engine)         self._session = DBSession()   class TestEmployee(MyEmployee):     def setUp(self):         self.db = emp.database.Database(db=options.connection)         self.db._session._autoflush()      @mock.patch.object(session.Session, 'add')          @mock.patch.object(session.Session, 'query')       def test_update(self, mock_query, mock_add):         employees = [{'id': 1,                       'name': 'Pradeep',                       'department': 'IT',                       'manager': 'John'}]         mock_add.side_effect = self.add_side_effect         mock_query.return_value = self.query_results()           self.update_employees(employees)      def add_side_effect(self, instance, _warn=True):         // Code to mock add         // Values will be stored in a dict which will be used to          // check with expected value.      def query_results(self):           m = MagicMock()           if self.count == 0:                m.return_value.filter.return_value.all.return_value = [employee]           elif:                m.return_value.filter.return_value.all.return_value = [department]           return m   

I have query_results as the method under test calls query twice. First the employee table and next the department table.

How do I mock this chained function call?

like image 863
Pradeep Avatar asked Dec 16 '15 09:12

Pradeep


People also ask

How do you mock a function 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 MagicMock Python?

To begin with, MagicMock is a subclass of Mock . class MagicMock(MagicMixin, Mock) As a result, MagicMock provides everything that Mock provides and more. Rather than thinking of Mock as being a stripped down version of MagicMock, think of MagicMock as an extended version of Mock.

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.

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.


2 Answers

m = MagickMock() m.session.query().filter().all.return_value = employees 

https://docs.python.org/3/library/unittest.mock.html

like image 58
Tate Thurston Avatar answered Sep 22 '22 13:09

Tate Thurston


I found a solution to a similar problem where I needed to mock out a nested set of filtering calls.

Given code under test similar to the following:

interesting_cats = (session.query(Cats)                            .filter(Cat.fur_type == 'furry')                            .filter(Cat.voice == 'meowrific')                            .filter(Cat.color == 'orande')                            .all()) 

You can setup mocks like the following:

mock_session_response = MagicMock() # This is the magic - create a mock loop mock_session_response.filter.return_value = mock_session_response # We can exit the loop with a call to 'all' mock_session_response.all.return_value = provided_cats  mock_session = MagicMock(spec=Session) mock_session.query.return_value = mock_session_response 
like image 30
Ron Dahlgren Avatar answered Sep 19 '22 13:09

Ron Dahlgren