How do you mock a return value from PyMySQL for testing in Python?

Question:

I’m trying to set up some tests for a script that will pull data from a MySQL database. I found an example here that looks like what I want to do, but it just gives me an object instead of results:

<MagicMock name='pymysql.connect().cursor[38 chars]152'>

Here is the function I am using (simple.py):

import pymysql

def get_user_data():
    connection = pymysql.connect(host='localhost', user='user', password='password',
                                 db='db', charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)

    try:
        with connection.cursor() as cursor:
            sql = "SELECT `id`, `password` FROM `users`"
            cursor.execute(sql)
            results = cursor.fetchall()
    finally:
        connection.close()

    return results

And the test:

from unittest import TestCase, mock
import simple

class TestSimple(TestCase):

    @mock.patch('simple.pymysql', autospec=True)
    def test_get-data(self, mock_pymysql):
        mock_cursor = mock.MagicMock()
        test_data = [{'password': 'secret', 'id': 1}]
        mock_cursor.fetchall.return_value = test_data
        mock_pymysql.connect.return_value.__enter__.return_value = mock_cursor

        self.assertEqual(test_data, simple.get_user_data())

The results:

AssertionError: [{'id': 1, 'password': 'secret'}] != <MagicMock name='pymysql.connect().cursor[38 chars]840'>

I’m using Python 3.51

Asked By: Tamerz

||

Answers:

It looks like your mock is missing a reference to the cursor:

mock_pymysql.connect.return_value.cursor.return_value.__enter__.return_value = mock_cursor

I’ve always found mocking call syntax to be awkward but the MagicMock displays what’s wrong in a roundabout way. It’s saying it has no return value registered for pymysql.connect.return_value.cursor

<MagicMock name='pymysql.connect().cursor[38 chars]840'>

Answered By: dm03514
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.