如何测试Flask中无返回值的数据库新增函数?
问题
我有一个向数据库添加新记录的Flask函数add_report_to_db,该函数无返回值,内部通过try-except捕获异常并使用flash给出提示。当前用unittest测试时,即便函数执行出现异常(比如传入无法转为float的longitude参数),函数仍返回None导致测试通过,请问如何验证函数未抛出任何异常?
函数代码
def add_report_to_db(latitude, longitude, color: str, comment: str): """Add a new report to the DB.""" try: report = Report( latitude=float(latitude), longitude=float(longitude), color=color, comment=comment, ip=request.remote_addr, ) db.session.add(report) db.session.commit() flash("Success!", category="success") except Exception as e: flash("Error." + str(e), category="error")
测试代码
class BasicsTestCase(unittest.TestCase): """General test cases.""" def setUp(self): """Execute before unit test. Create an app and in memory DB.""" self.app = create_app("testing") self.app_context = self.app.app_context() self.app_context.push() db.create_all() self.current_map = folium.Map(location=(50.45, 30.52)) self.client = self.app.test_client(use_cookies=True) report = Report( latitude=50.45, longitude=30.52, color="red", comment="comment", ip="127.0.0.1", ) db.session.add(report) db.session.commit() def tearDown(self): """Execute after unit test. Drop DB, session, app.""" db.session.remove() db.drop_all() self.app_context.pop() def test_add_report_to_db(self): """Test add a new report to the DB.""" with current_app.test_request_context(): result = add_report_to_db( latitude=50.45, longitude="testing", # 故意传入错误参数 color="red", comment="comment", ) self.assertIsNone(result) # 即使有异常测试也通过 self.assertRaises(not Exception, result) # 我需要类似这样的验证逻辑
解决方案
因为函数内部已经用try-except捕获了所有异常,所以它永远不会向外抛出异常,自然没法用assertRaises来检测。要验证函数是否成功执行(即没有触发except分支),可以从以下两个方面入手:
1. 检查Flash消息的内容和分类
函数执行成功时会触发flash("Success!", category="success"),异常时触发flash("Error." + str(e), category="error")。测试时可以通过Flask的get_flashed_messages(with_categories=True)来获取消息,判断是否是成功的那条:
修改测试用例如下:
def test_add_report_to_db_success(self): """测试成功添加记录到数据库""" with self.app.test_request_context(): add_report_to_db( latitude=50.45, longitude=30.53, # 合法的数值参数 color="red", comment="test comment", ) # 获取带分类的Flash消息 flashed_messages = get_flashed_messages(with_categories=True) # 验证是否存在成功消息 self.assertIn(("success", "Success!"), flashed_messages) # 额外验证数据库记录数是否增加 self.assertEqual(Report.query.count(), 2) def test_add_report_to_db_failure(self): """测试添加记录失败的场景""" with self.app.test_request_context(): add_report_to_db( latitude=50.45, longitude="testing", # 非法参数,触发异常 color="red", comment="test comment", ) flashed_messages = get_flashed_messages(with_categories=True) # 验证是否存在错误消息 self.assertTrue( any(category == "error" and msg.startswith("Error.") for category, msg in flashed_messages) ) # 验证数据库记录数未变化 self.assertEqual(Report.query.count(), 1)
2. 验证数据库状态变化
函数成功执行会向数据库新增一条记录,所以可以查询Report表的总记录数,确认是否比初始值多1条;如果执行失败,记录数应该保持不变。
原测试无效的原因
self.assertIsNone(result)永远为真:因为函数没有定义返回值,默认返回None,不管是否触发异常。self.assertRaises(not Exception, result)用法错误:assertRaises需要传入异常类和可调用对象,而不是函数执行后的结果。而且因为函数内部捕获了所有异常,它根本不会向外抛出异常,所以这个断言从逻辑上就不成立。
内容的提问来源于stack exchange,提问作者Vitalii Mytenko
相关产品推荐
相关产品推荐

