Python 3.4 AssertEqual()在Django单元测试中使用时的不可预测行为

时间:2016-01-06 14:29:50

标签: python django unit-testing

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

  

第113行,在test_index_view_with_questions_without_choices中       self.assertEqual(response.context [' lastest_question_list'],[])   断言错误:[]!= []

以下是测试本身:

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'], [])

这里有视图本身来显示Queryset的定义方式:

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

P.S。:我发现了HERE描述的类似问题,但我仍然对实际导致此类行为的原因感到困惑。即使我知道如何使测试在这个特定的例子中工作,但我仍然很重要的是要了解正在发生的事情。 :)

1 个答案:

答案 0 :(得分:1)

首先,我怀疑并且您检查过,response.context['latest_question_list']是一个查询集,因此您无法直接将查询集对象与列表对象进行比较。

此外,django doc中记录了assertQuerysetEqual,引用此处:

  

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

     

qs和值的内容的比较使用   功能转换;默认情况下,这意味着每个的repr()   比较价值。如果repr()没有,则可以使用任何其他可调用的   提供独特或有用的比较。

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