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?
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 .
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.
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.
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.
m = MagickMock() m.session.query().filter().all.return_value = employees
https://docs.python.org/3/library/unittest.mock.html
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With