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?
To write a test you derive from any of the Django (or unittest) test base classes (SimpleTestCase, TransactionTestCase, TestCase, LiveServerTestCase) and then write separate methods to check that specific functionality works as expected (tests use "assert" methods to test that expressions result in True or False values ...
Writing testsDjango's unit tests use a Python standard library module: unittest . This module defines tests using a class-based approach. When you run your tests, the default behavior of the test utility is to find all the test cases (that is, subclasses of unittest.
Which is better – pytest or unittest? Although both the frameworks are great for performing testing in python, pytest is easier to work with. The code in pytest is simple, compact, and efficient. For unittest, we will have to import modules, create a class and define the testing functions within that class.
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With