I'm trying to learn unit testing with Django/unittest.

These are simple versions of my models:

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)

And this is the test code I've come up with:

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])

The test results fails because on an AssertionError even though the string representations of device.get_ips() and [ip1, ip2, ip3] are identical.

If I try using self.assertListEqual I get an error because device.get_ips() is a QuerySet and not a list.

If I try self.assertQuerySetEqual I get an error saying "DeviceTest object has no attribute assertQuerySetEqual" but I'm not sure why because DeviceTest extends django.test's TestCase.

How should I be doing a test like this?

Also, in a "real" project would it make sense to do such a simple test?

有帮助吗?

解决方案 2

The call device.get_ips() returns a QuerySet whereas [ip1, ip2, ip3] is a list. Hence they're currently not equal.

Given that you don't want to test things that may not matter (order in which rows are returned in .filter() from the database), I suggest testing as follows:

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)

This tests: three results and IPs are the same. This should give reasonable confidence that you're getting the same objects (although you can add more assertions as desired).

其他提示

Actually the right way, and recommended by djangoproject is:

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

Forcing sorted on queryset and list will change your testing scenario and you don't want it.

You typed self.assertQuerySetEqual and it should be self.assertQuerysetEqual, try:

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

Or if you still want to test it against a list:

self.assertItemsEqual(device.get_ips(), [ip1, ip2, ip3])
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top