Skip to main content
 首页 » 编程设计

在 Django 单元测试中使用时的 Python 3.4 AssertEqual() 意外行为

2025年05月04日35dyllove98

我在 Django 单元测试 (Python 3.4) 中遇到了 AssertEquals() 的一些奇怪行为。以下测试导致这样的断言错误:

line 113, in test_index_view_with_questions_without_choices self.assertEqual(response.context['lastest_question_list'], []) AssertionError: [] != []

这是测试本身:

def test_index_view_with_questions_without_choices(self): 
    ''' 
    If a question has no choices it should not be 
    displayed on the questions index page no matter if it's 
    a past or a future question. 
    ''' 
    create_question_with_no_choices(question_text='no choices q1', days=-5) 
    create_question_with_no_choices(question_text='no choices q2', days=5) 
    response = self.client.get(reverse('polls:index')) 
    self.assertContains(response, 'No polls are available.', status_code=200) 
    self.assertEqual(response.context['lastest_question_list'], []) 

像这样更改最后一行:

self.assertEqual(len(response.context['lastest_question_list']), 0) 

使测试正常工作但我不明白它拒绝使用列表本身的原因。

我在同一个应用和项目中也有一个非常相似的测试,它工作得很好:

def test_index_view_with_no_questions(self): 
    ''' 
    If no questions exist, an appropriate message  
    should be displayed. 
    ''' 
    response = self.client.get(reverse('polls:index')) 
    self.assertEqual(response.status_code, 200) 
    self.assertContains(response, 'No polls are available.') 
    self.assertQuerysetEqual(response.context['lastest_question_list'], []) 

这是 View 本身,用于显示查询集是如何定义的:

class IndexView(generic.ListView): 
    template_name = 'polls/index.html' 
    context_object_name = 'lastest_question_list' 
 
    def get_queryset(self): 
        ''' 
        Returns last five published questions 
        (not including those set to be published in the future) 
        Also excludes the questions with an empty choice_set. 
        ''' 
        qset = Question.objects.annotate(choices_count=Count('choice')) 
        qset = qset.filter(choices_count__gte=1, pub_date__lte=timezone.now()) 
        qset = qset.order_by('-pub_date')[:5] 
 
        return qset 

附注:我发现一个类似的问题描述 HERE ,但我仍然对实际导致这种行为的原因感到困惑。尽管我知道如何在这个特定示例中进行测试,但了解正在发生的事情对我来说仍然很重要。 :)

请您参考如下方法:

首先,正如我所怀疑和您所检查的那样,response.context['latest_question_list'] 是一个查询集,因此您无法直接比较查询集对象和列表对象。

此外,assertQuerysetEqual 记录在 django doc 中, 在这里引用:

TransactionTestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True, msg=None)

The comparison of the contents of qs and values is performed using the function transform; by default, this means that the repr() of each value is compared. Any other callable can be used if repr() doesn’t provide a unique or helpful comparison.

您可以看到 assertQuerysetEqual 正在将查询集中的每个值与您提供的列表进行比较,因此它将遍历整个事物并比较每个值。这就是为什么它会通过测试但未通过 assertEqual 的原因。