문제

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