resolute
resolute

Reputation: 301

Mocking psycopg2 - how do I raise the exception?

I'm trying to handle potential execution problems with psycopg2 database. IIRC psycopg2.DatabaseError should handle most sql errors. The method inserts a html string into full_html column inside mytable and returns the id associated with it.

def insertPage(cursor, html):
    try:
       cursor.execute(("INSERT INTO mytable (full_html)"
        "VALUES (%s) RETURNING id"), (html,))
    except psycopg2.DatabaseError:
         print("error inserting html")

and the test:

def test_insertPage_error(self):
    mockPage = (1, 'html') # Row contains id and html string

    with patch('psycopg2.connect') as mock_connect:
        with self.assertRaises(psycopg2.DatabaseError):
            mock_cur = mock_connect.return_value.cursor.return_value
            mock_cur.fetchone.return_value = mockPage

            resultId = insertPage(mock_cur, 'html')

I'm having trouble invoking the psycopg2.DatabaseError. I've tried replacing 'html' argument with None or another value that's not a string. I'm thinking it's a problem with my mock_cur not returning what I want? Perhaps I'm misunderstanding the error i'm raising?

Traceback:

Traceback (most recent call last):
  File "/code/tests/testInsert.py", line 62, in test_insertPage_error
    resultId = insertPage(mock_cur, 'html')
AssertionError: DatabaseError not raised

Upvotes: 1

Views: 1976

Answers (1)

charlesreid1
charlesreid1

Reputation: 4841

Your insertPage() function is already catching the psycopg2.DatabaseError and printing a message instead, and exiting without raising another exception. That's why the DatabaseError never makes it out of the insertPage function.

Try changing your insertPage function to just make the cursor.execute call, without the try/except block, which will allow insertPage to pass the exception up the chain instead of catching it:

def insertPage(cursor, html):
   cursor.execute(("INSERT INTO mytable (full_html)"
        "VALUES (%s) RETURNING id"), (html,))

Alternatively, you could define a custom exception type and raise it when you encounter the DatabaseError:

class SpecialDatabaseError(Exception):
    pass

def insertPage(cursor, html):
    try:
       cursor.execute(("INSERT INTO mytable (full_html)"
        "VALUES (%s) RETURNING id"), (html,))
    except psycopg2.DatabaseError:
        raise SpecialDatabaseError("This is a special error!")

then your mock would assert that the SpecialDatabaseError is raised:

   with self.assertRaises(SpecialDatabaseError):

Upvotes: 2

Related Questions