Search code examples
pythonmockingflask-sqlalchemypytestpython-unittest.mock

unittest.mock doesn't work when tests are run with pytest


I have the following project structure:

tests/
└── messenger/
    └── messaging_test.py
app/
├── __init__.py
├── models.py
└── messenger/
    ├── __init__.py
    └── messaging.py

Inside messaging.py module there's a function send_schedule with the following lines:

talks = models.Talk.query.all()
raise ValueError(str(talks))  # the debug output

I'm trying to patch the models.Talk.query.all() call. Inside messaging_test.py there's the following test:

@patch('app.models.Talk.query.all')
def test_send_schedule(self, all_query_mock):
    all_query_mock.return_value = []
    for talk_id in range(1, 6):
        talk_mock = MagicMock(id=talk_id, title=str(talk_id), speaker_facebook_id=1)
        all_query_mock.return_value.append(talk_mock)
    with vcr.use_cassette('vcr_cassettes/send_schedule.yaml'):
        response = messaging.send_schedule(self.access_token, self.user_id)

    self.assertTrue('recipient_id' in response)
    self.assertTrue('message_id' in response)
    self.assertEqual(response['recipient_id'], self.user_id)

When I run the test with python3 -m pytest tests/messenger/messaging_test.py command, ValueError outputs an empty list, which signifies that the call wasn't patched. Can you suggest a fix to that?

What did I do to solve the issue:

  • Read "Where to patch" paragraph of documentation. This led me to suspicion that pytest runs my tests in a weird way.
  • Tried to use pytest-mock but failed to figure out how to use it with unittest.TestCase.

Solution

  • Okay, I clearly have done a bad research on this. There was no problem with pytest module. In order to fix the issue, I needed to patch app.models.Talk, not the strange app.models.Talk.query.all. After I patched the class, I simply added the properties I needed:

        @patch('app.models.Talk')
    def test_send_schedule(self, talk_class_mock):
        talk_mocks = []
        for talk_id in range(1, 6):
            talk_mock = MagicMock(id=talk_id, title=str(talk_id), speaker_facebook_id=1)
            talk_mocks.append(talk_mock)
        query_mock = MagicMock(all=MagicMock(return_value=talk_mocks))
        talk_class_mock.query = query_mock
        with vcr.use_cassette('vcr_cassettes/send_schedule.yaml'):
            response = messaging.send_schedule(self.access_token, self.user_id)
    
        self.assertTrue('recipient_id' in response)
        self.assertTrue('message_id' in response)
        self.assertEqual(response['recipient_id'], self.user_id)