19.4. Tests Models¶
Split tests into multiple files
shop/tests/__init__.py
must be present for tests to be discovered (can be empty)Use TestCase classes to split tests into logical groups
In order to use fixtures create a
fixtures
directory with a.json
file for each model
19.4.1. Example¶
from datetime import date
from django.db import models
from django.utils.translation import gettext_lazy as _
class Customer(models.Model):
firstname = models.CharField(verbose_name=_('First Name'), max_length=100)
lastname = models.CharField(verbose_name=_('Last Name'), max_length=100, db_index=True)
birthdate = models.DateField(verbose_name=_('Birthdate'), null=True, blank=True, default=None)
@property
def emails(self):
from shop.models import Email
return Email.objects.filter(customer=self)
@property
def name(self):
return f'{self.firstname} {self.lastname}'
@property
def age(self):
if not self.birthdate:
return None
year = 365.25
difference = date.today() - self.birthdate
return int(difference.days / year)
def __str__(self):
return f'{self.firstname} {self.lastname}'
class Meta:
app_label = 'shop'
verbose_name = _('Customer')
verbose_name_plural = _('Customers')
from datetime import date
from unittest.mock import patch
from django.test import TestCase
from shop.models import Customer, Email, EmailType
class CustomerCreateTest(TestCase):
def test_customer_with_firstname_and_lastname(self):
customer = Customer.objects.create(firstname='Mark', lastname='Watney')
self.assertEqual(customer.firstname, 'Mark')
self.assertEqual(customer.lastname, 'Watney')
def test_customer_with_birthdate(self):
customer = Customer.objects.create(firstname='Mark', lastname='Watney', birthdate=date(2000, 1, 2))
self.assertEqual(customer.birthdate, date(2000, 1, 2))
class CustomerFunctionalityTest(TestCase):
# fixtures = ['customer.json']
def setUp(self):
self.customer = Customer.objects.create(firstname='Mark', lastname='Watney')
self.email1 = Email.objects.create(customer=self.customer, type=EmailType.WORK, address='mwatney@nasa.gov')
self.email2 = Email.objects.create(customer=self.customer, type=EmailType.HOME, address='mwatney@gmail.com')
def test_customer_emails(self):
self.assertEqual(self.customer.emails.count(), 2)
self.assertListEqual(list(self.customer.emails), [self.email1, self.email2])
def test_customer_name(self):
self.assertEqual(self.customer.name, 'Mark Watney')
def test_customer_str(self):
self.assertEqual(str(self.customer), 'Mark Watney')
def test_customer_age_hardcoded(self):
self.customer.birthdate = date(2000, 1, 2)
self.assertEqual(self.customer.age, 24)
def test_customer_age_patch(self):
self.customer.birthdate = date(2000, 1, 2)
with patch('shop.models.customer.date') as d:
d.today.return_value = date(2024, 1, 2)
self.assertEqual(self.customer.age, 24)
19.4.2. Use Case - 0x01¶
from django.db import models
from django.utils.translation import gettext_lazy as _
class EmailType(models.TextChoices):
HOME = 'home', _('Home')
WORK = 'work', _('Work')
class Email(models.Model):
customer = models.ForeignKey(verbose_name=_('Customer'), to='shop.Customer', on_delete=models.CASCADE, null=False, blank=False, db_index=True)
type = models.CharField(verbose_name=_('Type'), max_length=100, choices=EmailType, null=False, blank=False, default=EmailType.HOME)
address = models.EmailField(verbose_name=_('Address'), max_length=100, null=False, blank=False, unique=True)
def __str__(self):
return f'{self.customer.name} <{self.address}>'
class Meta:
app_label = 'shop'
verbose_name = _('Email')
verbose_name_plural = _('Emails')
from django.test import TestCase
from shop.models import Customer, Email, EmailType
class EmailCreateTest(TestCase):
def setUp(self):
self.customer = Customer.objects.create(firstname='Mark', lastname='Watney')
def test_email_with_type_default(self):
Email.objects.create(customer=self.customer, address='mwatney@gmail.com')
email = Email.objects.get(customer=self.customer)
self.assertEqual(email.type, EmailType.HOME)
def test_email_with_type_work(self):
Email.objects.create(customer=self.customer, type=EmailType.WORK, address='mwatney@nasa.gov')
email = Email.objects.get(customer=self.customer, type=EmailType.WORK)
self.assertEqual(email.address, 'mwatney@nasa.gov')
self.assertEqual(email.type, EmailType.WORK)
def test_email_with_type_home(self):
Email.objects.create(customer=self.customer, type=EmailType.HOME, address='mwatney@gmail.com')
email = Email.objects.get(customer=self.customer, type=EmailType.HOME)
self.assertEqual(email.address, 'mwatney@gmail.com')
self.assertEqual(email.type, EmailType.HOME)
class EmailFunctionalityTest(TestCase):
def setUp(self):
self.customer = Customer.objects.create(firstname='Mark', lastname='Watney')
self.email = Email.objects.create(customer=self.customer, address='mwatney@gmail.com')
def test_email_str(self):
self.assertEqual(str(self.email), 'Mark Watney <mwatney@gmail.com>')
19.4.3. Further Reading¶
Python TDD, advanced OOP and refactoring https://www.youtube.com/watch?v=Yy-S14XJ5Bc&pp=ygUQaGFyYXN5bWN6dWsgdGRkIA%3D%3D
19.4.4. Assignments¶
# doctest: +SKIP_FILE
"""
* Assignment: Django Tests Shop
* Complexity: medium
* Lines of code: 33 lines
* Time: 34 min
English:
0. Install `Pillow` package:
`python -m pip install --upgrade pillow`
1. Use `myproject` project
2. Use `shop` app
3. Create model `Customer`:
a. `firstname` - first name
b. `lastname` - last name
c. `birthdate` - date of birth
4. Create unit tests for model
5. Use TDD method to write tests
Polish:
0. Zainstaluj pakiet `Pillow`:
`python -m pip install --upgrade pillow`
1. Użyj projekt `myproject`
2. Użyj apkę `shop`
3. Stwórz model `Customer` z polami:
a. `firstname` - imię
b. `lastname` - nazwisko
c. `birthdate` - data urodzenia
4. Stwórz testy jednostkowe do modelu
5. Użyj metody TDD pisania testów
Hints:
* models.CharField
* models.DateField
"""