测试SQLAlchemy代码抛出IntegrityError的适当方法是什么?

5

我已经阅读了 这篇 问答,并尝试在我的代码中捕获引发IntegrityError异常的异常,如下:

self.assertRaises(IntegrityError, db.session.commit())

但是,我的单元测试仍然失败,并停止于IntegrityError异常。我希望它显示OK,因为我已经预期在我的单元测试中出现异常。 这是由尝试插入具有相同唯一字段值的行的代码引起的。
有什么想法吗?
2个回答

6
以下任何一种都可以解决问题:
# ... only if version >= 2.7
with self.assertRaises(IntegrityError):
    db.session.commit()

或者:

self.assertRaises(IntegrityError, db.session.commit)

您的示例与正确方式之间的区别在于:
# Your example: You call db.session.commit(), this will raise an exception before
# assertRaises is called
self.assertRaises(IntegrityError, db.session.commit())

# Correct way: Pass what should be called to assertRaises, 
# let assertRaises invoke it and check for exception
self.assertRaises(IntegrityError, db.session.commit)

我更喜欢使用assertRaises作为上下文管理器(使用with)。


哎呀,这解决了我的问题,让我感到开心!谢谢! :) 对的,我之前想过参数接受函数名而不是函数调用。但是,当我实际编写代码时,不知怎么就忘了这一点。但是,你为什么更喜欢使用上下文管理器呢?使用这个单行代码不是结果也会相同吗? - swdev
添加评论,我按照您指出的使用上下文管理器,而且我认为另一个好处是我们可以在缩进块中扩展/完善我们的代码。我仍然是 Python 的新手,所以这就是我得到的 :) - swdev
1
我同意。我认为使用assertRaises作为上下文管理器可以使测试代码更清晰。 - codeape

0
我刚刚花了几个小时试图弄清楚为什么我的测试在执行过程中出现了IntegrityError错误,但是无法通过pytest.raises块捕获它(会话构建器已简化,但请注意autocommit标志):
async with async_session_maker(autocommit=True) as session:
    with pytest.raises(sqlalchemy.exc.IntegrityError):
        sqlachemy.execute(statement_which_violates_foreign_key_contstraint)

问题出现在一个会话块和pytest块的订单上。异常将在session.commit()语句上引发,该语句隐藏在AsyncSession的__aexit__方法中。

解决方案 - 改变顺序:

with pytest.raises(sqlalchemy.exc.IntegrityError):
    async with async_session_maker(autocommit=True) as session:
        sqlachemy.execute(statement_which_violates_foreign_key_contstraint)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接