如何使用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
相关产品推荐
相关产品推荐

