3

MagicMock name='con.cursor.fetchall' id='a121213312' I want to have value when I call read function

db.py

try:
    con = psycopg2.connect(
                    host="yhvh",
                    database="python_db",
                    user="postgres",
                    password="ichoose",
                    )
except:
    print("Unable to connect database")

# Open a cursor to perform database operation
cur = con.cursor()

def read(con):
    """
    Read data in Database
    """
    print("Read")
    cur = con.cursor()

    # execute the query
    data ="SELECT id, name FROM employees"
    cur.execute(
        data
    )
    # fetchall - returns all entries
    rows = cur.fetchall()

    for r in rows:
        print(f"id {r[0]} name {r[1]}")

    return rows

test_db.py

class TestDb(unittest.TestCase):
    """
    Study
        - Mock and Unittes
    """
    def test_read(self):
        expected = (9, 'jibreel')

        with patch("db.con") as mock_connect:
            mock_con = mock_connect.return_value
            mock_cur = mock_con.cursor.return_value
            mock_cur.fetchall.return_value = expected

            result = db.read(mock_connect)
            print(result)
            self.assertEqual(result, expected)


The error when I test it

AssertionError: MagicMock name='con.cursor.fetchall' id='a121213312' != (9, 'jibreel')

1
  • What is the printed output of the variable result? Commented Jul 29, 2019 at 7:56

1 Answer 1

3

There are quite a few things going on here:

  • You're trying to mock a variable internal to your module that you don't really export. I'm not sure if you can actually achieve that, but you don't need to. Your read function takes a connection as an argument and you can use the mock for that.

  • You're going to have a list of rows, which is basically a list of lists, but in your return value you have a single row, which will make your for loop fail (because at the first loop r will be 9 and r[0] will fail)

  • As a side note: please don't call your modules with names like db.py, there is a chance that some pre-made module will have the same name and that could cause some import issue

So, if I get correctly what you want, you might want to try something like:

import unittest
from unittest.mock import MagicMock
import db # Consider renaming this


class TestDb(unittest.TestCase):
    def test_read(self):
        expected = [(9, 'jibreel')]

        mock_connect = MagicMock()
        mock_cursor = MagicMock()
        mock_cursor.fetchall.return_value = expected
        mock_connect.cursor.return_value = mock_cursor

        result = d.read(mock_connect)
        self.assertEqual(result, expected)

It could probably be simplified a bit, but this should work.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, @ChatterOne. Learn new about mocking and testing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.