Domanda

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?

È stato utile?

Soluzione 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).

Altri suggerimenti

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])
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top