如何对使用raw()与annotate()的Django RawQuerySet做单元测试?
测试方案针对Django raw() + annotate() 查询
针对你用Django结合raw()原生SQL和annotate()注解的查询场景,我整理了一套实用的测试方案,结合你的代码示例来一步步拆解:
1. 基础结构与数据类型验证
先从最基础的开始,确保查询返回的对象包含所有预期字段,且字段类型符合定义:
from django.test import TestCase from myapp.models import MyModel from otherapp.models import OtherModel class MyQueryTestCase(TestCase): def setUp(self): # 提前创建测试关联数据 self.other_obj = OtherModel.objects.create(other_column1=123, other_column2="test_value") self.my_model_obj = MyModel.objects.create(column1="foo", column2="bar", othermodel=self.other_obj) def test_query_field_presence_and_types(self): # 调用你的查询方法(替换成实际方法名) query_result = your_query_function() self.assertEqual(len(query_result), 1) result_obj = query_result[0] # 验证基础模型字段存在 self.assertTrue(hasattr(result_obj, 'id')) self.assertTrue(hasattr(result_obj, 'column1')) self.assertTrue(hasattr(result_obj, 'column2')) # 验证注解字段存在且类型正确 self.assertTrue(hasattr(result_obj, 'other_column1')) self.assertIsInstance(result_obj.other_column1, int) self.assertTrue(hasattr(result_obj, 'other_column2')) self.assertIsInstance(result_obj.other_column2, str) # 按实际字段类型调整
2. 注解字段值正确性验证
因为你用annotate()+Value()绑定了关联表的字段,要确保返回的值和数据库中存储的一致:
def test_annotated_field_value_accuracy(self): query_result = your_query_function() result_obj = query_result[0] # 直接对比注解字段和原关联模型的实际值 self.assertEqual(result_obj.other_column1, self.other_obj.other_column1) self.assertEqual(result_obj.other_column2, self.other_obj.other_column2)
3. JOIN关联逻辑完整性测试
你的原生SQL用了INNER JOIN,要验证关联逻辑是否符合预期:
def test_join_logic_correctness(self): # 创建一个无关联的MyModel实例 MyModel.objects.create(column1="no_association", column2="test") query_result = your_query_function() # INNER JOIN会过滤掉无关联的实例,所以返回数量应为1 self.assertEqual(len(query_result), 1) # 创建第二个关联实例 MyModel.objects.create(column1="foo2", column2="bar2", othermodel=self.other_obj) query_result = your_query_function() self.assertEqual(len(query_result), 2)
4. 边界场景与异常处理测试
覆盖空数据、特殊值等边缘情况,确保查询鲁棒性:
def test_empty_data_scenario(self): # 清空所有测试数据 MyModel.objects.all().delete() OtherModel.objects.all().delete() query_result = your_query_function() self.assertEqual(len(query_result), 0) def test_special_value_handling(self): # 创建包含特殊值的关联实例 special_other = OtherModel.objects.create(other_column1=0, other_column2="") MyModel.objects.create(column1="special_case", column2="test", othermodel=special_other) query_result = your_query_function() result_obj = query_result[0] self.assertEqual(result_obj.other_column1, 0) self.assertEqual(result_obj.other_column2, "")
5. 原生SQL与ORM结果一致性验证
如果担心原生SQL和annotate的结合可能出现偏差,可以直接对比原生SQL执行结果和ORM查询结果:
from django.db import connection def test_raw_sql_vs_orm_consistency(self): # 直接执行原生SQL with connection.cursor() as cursor: cursor.execute("""SELECT table1.id, table1.column1, table1.column2, table2.other_column1, table2.other_column2 FROM myapp_mymodel as table1 JOIN otherapp_othermodel as table2 ON table1.othermodel_id = table2.id""") raw_db_result = cursor.fetchone() # 获取ORM查询结果 orm_result = your_query_function()[0] # 逐字段对比确保一致 self.assertEqual(raw_db_result[0], orm_result.id) self.assertEqual(raw_db_result[1], orm_result.column1) self.assertEqual(raw_db_result[2], orm_result.column2) self.assertEqual(raw_db_result[3], orm_result.other_column1) self.assertEqual(raw_db_result[4], orm_result.other_column2)
这些测试覆盖了基础验证、数据准确性、关联逻辑和边缘场景,能帮你确保查询的稳定性。如果你的实际场景有过滤、排序等额外逻辑,可以在这些基础用例上扩展对应的测试。
内容的提问来源于stack exchange,提问作者NickCatal
相关产品推荐
相关产品推荐

