模拟 psycopg2 - 如何引发异常?

Mocking psycopg2 - how do I raise the exception?

我正在尝试处理 psycopg2 数据库的潜在执行问题。 IIRC psycopg2.DatabaseError 应该可以处理大多数 sql 错误。该方法将 html 字符串插入到 mytable 和 returns 内的 full_html 列中 id 与其关联。

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

和测试:

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')

我在调用 psycopg2.DatabaseError 时遇到问题。我尝试用 None 或其他不是字符串的值替换 'html' 参数。我在想我的 mock_cur 没有返回我想要的东西有问题吗?也许我误解了我提出的错误?

回溯:

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

您的 insertPage() 函数已经在捕获 psycopg2.DatabaseError 并改为打印一条消息,并且在不引发另一个异常的情况下退出。这就是为什么 DatabaseError 永远不会脱离 insertPage 函数。

尝试将您的 insertPage 函数更改为仅进行 cursor.execute 调用,而不使用 try/except 块,这将允许 insertPage 将异常传递到链中抓住它:

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

或者,您可以定义自定义异常类型并在遇到 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!")

然后你的模拟会断言 SpecialDatabaseError 被引发:

   with self.assertRaises(SpecialDatabaseError):