You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:30:01