如何编写单元测试验证Django模型表单有效性?解决验证失败问题
问题分析与解决方案
你的测试失败主要有两个核心原因,咱们一步步拆解:
1. 表单初始化时未传入对应Question实例
在QuestionForm的__init__方法里,你是通过self.instance.pk来过滤该问题对应的Option的,但在测试中创建表单时,你只传了data=data,没有传入instance=question_1。这时候self.instance是一个空的Question对象,pk为None,导致Option.objects.filter(question_id=self.instance.pk)返回空集合,表单的selected_option字段根本没有可用选项,自然任何输入都会被判为非法。
2. 测试数据的selected_option值不匹配
你的表单selected_option字段的choices是用Option的主键作为值((f'{option.pk}', f'{option}')),但测试里传的是option_1.option_text,两者完全不匹配,这也会触发"选项不属于可用范围"的错误。
修复后的测试代码
修改test_valid_data函数如下:
def test_valid_data(self): # 创建关联的Collection、Question、Option实例 collection = Collection.objects.create() question_1 = Question.objects.create( question_text='What is the width of the telephone?', date_published=timezone.now(), collection=collection ) option_1 = question_1.options.create( option_text='Five centimetres' ) # 注意:这里要传入instance=question_1,并且selected_option传option的pk data = { 'question_text': question_1.question_text, 'selected_option': str(option_1.pk), # 转成字符串,因为choices里的键是字符串格式 } form = QuestionForm(data=data, instance=question_1) self.assertTrue(form.is_valid())
额外优化建议
为了避免后续出现类似问题,你可以在表单的__init__里增加对instance的判断,比如当instance未保存(pk不存在)时,隐藏selected_option字段或者给出提示:
def __init__(self, *args, **kwargs): super(QuestionForm, self).__init__(*args, **kwargs) if self.instance.pk: # 只有当Question已经保存到数据库时才加载选项 self.fields['selected_option'] = forms.ChoiceField( choices=[(str(option.pk), str(option)) for option in self.instance.options.all()], widget=RadioSelect, required=True, error_messages={ 'required': 'The question form lacks a selected_option' } ) else: # 如果是新建Question,可以移除该字段或者设置为非必填 self.fields.pop('selected_option', None)
这样处理后,表单的行为会更健壮,也能避免在未传入有效instance时出现无选项的情况。
内容的提问来源于stack exchange,提问作者user10755417
相关产品推荐
相关产品推荐

