Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
504 views
in Technique[技术] by (71.8m points)

python - 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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...