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

如何使用factory-boy为Django过滤器编写测试用例

编写Django FilterSet测试用例(结合factory-boy)

嘿,我来帮你搞定这个过滤器的测试用例!结合factory-boy生成测试数据的话,咱们可以按以下步骤来写:

1. 先创建模型对应的Factory类

首先得用factory-boy快速生成符合要求的测试数据,给你的模型写一个Factory:

import factory
from myapp.models import modelname  # 替换成你实际的模型路径

class ModelNameFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = modelname

    # 用Faker生成有真实感的测试数据,也可以写固定值
    name = factory.Faker('company')
    id = factory.Sequence(lambda n: n + 100)  # 避开默认自增ID的冲突
    price = factory.Faker('pydecimal', left_digits=3, right_digits=2, positive=True)

2. 编写测试类验证过滤器

接下来用Django的TestCase,结合Factory生成的数据,针对每个过滤场景写测试方法:

from django.test import TestCase
from myapp.filters import filter  # 这里强烈建议把过滤器类名改成ModelNameFilter,避免和Python内置filter重名
from myapp.models import modelname
from myapp.factories import ModelNameFactory

class ModelNameFilterTests(TestCase):
    @classmethod
    def setUpTestData(cls):
        # 一次性创建测试数据,所有测试方法共享,提升效率
        cls.apple_item1 = ModelNameFactory(name="Apple", price=10.99)
        cls.apple_item2 = ModelNameFactory(name="Apple", price=15.99)
        cls.banana_item = ModelNameFactory(name="Banana", price=5.99)
        cls.specific_id_item = ModelNameFactory(id=200, price=20.99)

    def test_filter_by_exact_name(self):
        # 验证按名称精确过滤的结果
        filter_instance = filter(data={'name': 'Apple'}, queryset=modelname.objects.all())
        
        # 先确认过滤器参数合法
        self.assertTrue(filter_instance.is_valid())
        
        # 检查过滤后的结果数量和内容
        filtered_queryset = filter_instance.qs
        self.assertEqual(filtered_queryset.count(), 2)
        self.assertIn(self.apple_item1, filtered_queryset)
        self.assertIn(self.apple_item2, filtered_queryset)

    def test_filter_by_exact_id(self):
        # 验证按ID精确过滤
        filter_instance = filter(data={'id': self.specific_id_item.id}, queryset=modelname.objects.all())
        self.assertTrue(filter_instance.is_valid())
        
        filtered_queryset = filter_instance.qs
        self.assertEqual(filtered_queryset.count(), 1)
        self.assertEqual(filtered_queryset.first(), self.specific_id_item)

    def test_filter_by_exact_price(self):
        # 验证按价格精确过滤
        filter_instance = filter(data={'price': '5.99'}, queryset=modelname.objects.all())
        self.assertTrue(filter_instance.is_valid())
        
        filtered_queryset = filter_instance.qs
        self.assertEqual(filtered_queryset.count(), 1)
        self.assertEqual(filtered_queryset.first(), self.banana_item)

    def test_multiple_filter_parameters(self):
        # 验证多参数组合过滤
        filter_instance = filter(data={'name': 'Apple', 'price': '10.99'}, queryset=modelname.objects.all())
        self.assertTrue(filter_instance.is_valid())
        
        filtered_queryset = filter_instance.qs
        self.assertEqual(filtered_queryset.count(), 1)
        self.assertEqual(filtered_queryset.first(), self.apple_item1)

    def test_no_filter_parameters(self):
        # 验证不带参数时返回所有数据
        filter_instance = filter(data={}, queryset=modelname.objects.all())
        self.assertTrue(filter_instance.is_valid())
        
        self.assertEqual(filter_instance.qs.count(), 4)

一些实用提示

  • 务必把过滤器类名从filter改成和模型对应的名称(比如ProductFilter),避免和Python内置的filter()函数重名,减少不必要的bug。
  • 如果之后你给过滤器添加了复杂规则(比如模糊查询icontains、价格范围gte/lte),只需要对应新增测试方法即可。比如测试名称模糊匹配:
    def test_filter_by_name_contains(self):
        # 假设你把name字段配置成了icontains过滤
        filter_instance = filter(data={'name__icontains': 'app'}, queryset=modelname.objects.all())
        self.assertTrue(filter_instance.is_valid())
        self.assertEqual(filter_instance.qs.count(), 2)
    
  • setUpTestData是Django提供的高效数据初始化方式,只会在测试类启动时执行一次,比每个测试方法单独创建数据快很多。

内容的提问来源于stack exchange,提问作者Mayar Khaled

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 10:17:45