【问题标题】:Unit testing a Django query set单元测试 Django 查询集
【发布时间】:2013-11-26 19:03:04
【问题描述】:

我正在尝试使用 Django/unittest 学习单元测试。

这些是我的模型的简单版本:

class Device(models.Model):
    name = models.CharField(max_length=100)

    def get_ips(self):
        return DeviceIP.objects.filter(device=self.id)


class DeviceIP(models.Model):
    ip = models.GenericIPAddressField()
    device = models.ForeignKey(Device)

这是我想出的测试代码:

from django.test import TestCase

class DeviceTest(TestCase):

    def test_get_ips(self):
        device = Device()
        device.name = 'My Device'

        ip1 = DeviceIP()
        ip1.ip = '127.0.0.1'
        ip1.device = device
        ip1.save()

        ip2 = DeviceIP()
        ip2.ip = '127.0.0.2'
        ip2.device = device
        ip2.save()

        ip3 = DeviceIP()
        ip3.ip = '127.0.0.3'
        ip3.device = device
        ip3.save()

        self.assertEqual(device.get_ips(), [ip1, ip2, ip3])

测试结果失败,因为在 AssertionError 上,即使 device.get_ips()[ip1, ip2, ip3] 的字符串表示形式相同。

如果我尝试使用 self.assertListEqual 会收到错误,因为 device.get_ips() 是一个 QuerySet 而不是一个列表。

如果我尝试self.assertQuerySetEqual,我会收到一条错误消息“DeviceTest object has no attribute assertQuerySetEqual”,但我不知道为什么,因为DeviceTest 扩展了django.test 的TestCase。

我应该如何做这样的测试?

另外,在“真实”项目中进行这样一个简单的测试是否有意义?

【问题讨论】:

  • 您知道使用device.deviceip_set.all() 是Django 内置的方法来执行您的get_ips() 方法吗?查看 Django 的文档以了解反向外键。你也不需要测试它,因为它是标准的 Django 行为。
  • 感谢@Ben,我才刚刚开始学习 Django,并没有意识到这一点。我将改用这种方法。

标签: python django django-unittest python-unittest


【解决方案1】:

其实是正确的,djangoproject推荐的方法是:

    self.assertEqual(list(device.get_ips()), [ip1, ip2, ip3])

在查询集和列表上强制 sorted 会改变您的测试场景,而您不想要它。

【讨论】:

    【解决方案2】:

    调用device.get_ips() 返回一个QuerySet[ip1, ip2, ip3] 是一个列表。因此它们目前不相等。

    鉴于您不想测试可能无关紧要的事情(从数据库中返回 .filter() 中的行的顺序),我建议进行如下测试:

    results = device.get_ips()
    result_ips = [ip.ip for ip in results]
    self.assertEqual(len(results), 3)
    self.assertTrue(ip1.ip in result_ips)
    self.assertTrue(ip2.ip in result_ips)
    self.assertTrue(ip3.ip in result_ips)
    

    这个测试:三个结果和IP是一样的。这应该让您有理由相信您会得到相同的对象(尽管您可以根据需要添加更多断言)。

    【讨论】:

    • 或者由于输入是唯一的,只需在断言中应用排序,这将同时处理列表长度和内容。 self.assertEqual(sorted(result_ips), sorted([ip1,ip, ip2.ip, ip3.ip]))
    • 感谢您的回答和对我有用的评论。我将按照上面 Ben 的建议改为使用 deviceip_set(),但这正是我需要了解如何进行此类测试的内容。 @AustinPhillips,小错误:ip1,ip 应该是 ip1.ip
    【解决方案3】:

    你输入了self.assertQuerySetEqual,应该是self.assertQuerysetEqual,试试:

    self.assertQuerysetEqual(device.get_ips(), [repr(ip1), repr(ip2), repr(ip3)], 
                             ordered=False)
    

    或者,如果您仍想针对列表进行测试:

    self.assertItemsEqual(device.get_ips(), [ip1, ip2, ip3])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-19
      • 2018-04-16
      • 2021-02-08
      • 2017-05-05
      • 1970-01-01
      • 2012-03-20
      • 2020-06-05
      • 1970-01-01
      相关资源
      最近更新 更多