简体   繁体   中英

How to catch sqlite3.IntegrityError with pytest.raises?

I am trying to catch a sqlite3.IntegrityError error with pytest.raises() . Here's some toy code to illustrate the behavior.

import sqlite3

import pytest


def func(cursor):
    try:
        cursor.execute("INSERT INTO Test (Name) VALUES ('Entry1')")
    except sqlite3.IntegrityError as e:
        print(e)


def test_func():
    connection = sqlite3.connect(":memory:")
    c = connection.cursor()

    c.execute(
        """
        CREATE TABLE IF NOT EXISTS Test (
        ID INTEGER PRIMARY KEY AUTOINCREMENT,
        Name TEXT UNIQUE NOT NULL)
        """
    )

    c.execute("INSERT INTO Test (Name) VALUES ('Entry1')")

    with pytest.raises(sqlite3.IntegrityError) as e:
        func(cursor=c)

    assert str(e.value) == "UNIQUE constraint failed: Test.Name"

The code of my func actually throws the anticipated error and prints to stdout, because Entry1 is already in the table and violates the UNIQUE restriction. However, the test fails. I don't understand why pytest didn't raise a sqlite3.IntegrityError . Here's the test's output:

FAILED                                                 [100%]UNIQUE constraint failed: Test.Name

err.py:12 (test_func)
def test_func():
        connection = sqlite3.connect(":memory:")
        c = connection.cursor()
    
        c.execute(
            """
            CREATE TABLE IF NOT EXISTS Test (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            Name TEXT UNIQUE NOT NULL)
            """
        )
    
        c.execute("INSERT INTO Test (Name) VALUES ('Entry1')")
    
        with pytest.raises(sqlite3.IntegrityError) as e:
>           func(cursor=c)
E           Failed: DID NOT RAISE <class 'sqlite3.IntegrityError'>

err.py:28: Failed

The reason is that you have already defined a try-catch block inside your function func , when the sqlite3.IntegrityError exception occurs, it is handled by the except inside your function rather than letting it be raised by pytest.raises . So just remove the try-except from your method and only keep the cursor.execute statement (or create a new one without it and use it in your test methods) or instead of handling the exception inside your func 's except block, you can raise it again.

Simple reproducible example:

def f():
    try:
        print(1/0)
    except ZeroDivisionError as e:
        print(e)

def g():
    print(1/0)

def a():
    with pytest.raises(ZeroDivisionError) as e:
        f()
        # g()

This will raise the exception inside your f() and then throw Failed: DID NOT RAISE <class 'ZeroDivisionError'> . If you call g() instead, it will execute normally.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM