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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.