【问题标题】:Assert that two lists of objects are equal in django testing断言两个对象列表在 Django 测试中是相等的
【发布时间】:2014-07-22 03:20:45
【问题描述】:

有没有办法在 django 测试中检查两个对象列表是否相等。

假设我有一些模型:

class Tag(models.Model):
    slug = models.SlugField(max_length=50, unique=True)
    def __unicode__(self):
        return self.slug

然后我运行这个简单的测试:

def test_equal_list_fail(self):
    tag_list = []
    for tag in ['a', 'b', 'c']:
        tag_list.append(Tag.objects.create(slug=tag))

    tags = Tag.objects.all()

    self.assertEqual(tag_list, tags)

这失败了:

======================================================================
FAIL: test_equal_list_fail (userAccount.tests.ProfileTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "path/to/tests.py", line 155, in test_equal_list_fail
    self.assertEqual(tag_list, tags)
AssertionError: [<Tag: a>, <Tag: b>, <Tag: c>] != [<Tag: a>, <Tag: b>, <Tag: c>]

----------------------------------------------------------------------

这将起作用:

def test_equal_list_passes(self):
    tag_list = []
    for tag in ['a', 'b', 'c']:
        tag_list.append(Tag.objects.create(slug=tag))

    tags = Tag.objects.all()

    for tag_set in zip(tags, tag_list):
        self.assertEqual(*tag_set)

但是,这失败了:

def test_equal_list_fail(self):
    tag_list = []
    for tag in ['a', 'b', 'c']:
        tag_list.append(Tag.objects.create(slug=tag))

    tags = Tag.objects.all()

    for tag_set in zip(tags, tag_list):
        print "\n"
        print tag_set[0].slug + "'s pk is %s" % tag_set[0].pk
        print tag_set[1].slug + "'s pk is %s" % tag_set[1].pk
        print "\n"
        self.assertIs(*tag_set)

与:

Creating test database for alias 'default'...
.......

a's pk is 1
a's pk is 1

F.
======================================================================
FAIL: test_equal_list_fail (userAccount.tests.ProfileTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "path/to/tests.py", line 160, in test_equal_list_fail
    self.assertIs(*tag_set)
AssertionError: <Tag: a> is not <Tag: a>

这是预期的行为吗?

编辑回应评论
这种比较有效:

class Obj:
    def __init__(self, x):
        self.x = x

>>> one = Obj(1)
>>> two = Obj(2)
>>> a = [one, two]
>>> b = [one, two]
>>> a == b
True

为什么其他数组的测试失败了?

【问题讨论】:

  • zip() 起作用的原因是标签的文本表示是 slug,这就是您要比较的内容。
  • 为什么不比较数组做同样的事情?我将编辑我的问题以显示示例

标签: django django-testing django-tests


【解决方案1】:

测试两个列表

使用:assertSequenceEqual

因为在这种情况下,tags = Tag.objects.all() 会生成一个 django.db.models.query.QuerySet,而 tag_list.append(...) 会创建一个列表。

不同情况下的其他选项有:

  • assertListEqual(a, b)
  • assertTupleEqual(a, b)
  • assertSetEqual(a, b)
  • assertDictEqual(a, b)

为什么&lt;Tag: a&gt; is not &lt;Tag: a&gt;

标签是相同的模型,但它们被加载到内存中的不同位置

for tag_set in zip(tags, tag_list):
    print "\n"
    print tag_set[0].slug + "'s pk is %s" % tag_set[0].pk + ' id is: ' + id(tag_set[0])
    print tag_set[1].slug + "'s pk is %s" % tag_set[1].pk + ' id is: ' + id(tag_set[1])
    print "\n"
    self.assertIs(*tag_set)

返回

.......

a's pk is 1 id is: 4522000208
a's pk is 1 id is: 4522228112

F.

因此,is 将返回 False

【讨论】:

    【解决方案2】:

    我认为您要测试的是创建的标签是否与您的测试列表中的标签具有相同的 slug。

    为此,使用values_list 仅获取 slug 作为列表,然后进行比较:

    assertEqual(Tag.objects.values_list('slug', flat=True), ['a','b','c'])
    

    我不得不说,这不是一个很有用的测试,因为您正在检查 django orm 功能,该功能已经过很好的测试。

    您的测试应该检查您自己的应用程序的细节。

    【讨论】:

    • hmm values_list 是一个很好的技巧,为此 +1。我同意,在这种情况下,这是一个无用的测试。我只是想要一个简单的例子来显示测试失败。我的实际测试并非如此微不足道。我不想使用 slug,因为我想检查实际模型是否相等,但我想可以用他们的pks
    • 不要使用pk,因为它们是增量的(很可能)并且两个主键不相等(如果它们是你有更大的问题,它们不应该)。如果所需的功能是防止重复,请使用unique_together 帮助在数据库级别执行此操作。
    • 您能否详细说明在这种情况下如何使用unique_together?我不清楚。
    猜你喜欢
    • 2014-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 2010-11-13
    相关资源
    最近更新 更多