from django.test import TestCase
from django.utils import timezone
import datetime
class LoanModelTests(TestCase):
def setUp(self):
self.owner = User.objects.create_user("priya")
self.borrower = User.objects.create_user("theo")
self.category = Category.objects.create(name="Power Tools")
self.tool = Tool.objects.create(name="Drill", owner=self.owner, category=self.category)
def test_is_overdue_true_past_due_date(self):
loan = Loan.objects.create(
tool=self.tool, borrower=self.borrower, status="approved",
due_date=timezone.now().date() - datetime.timedelta(days=1),
)
self.assertTrue(loan.is_overdue)
def test_browse_page_does_not_reintroduce_n_plus_1(self):
for i in range(5):
Tool.objects.create(name=f"Tool {i}", owner=self.owner, category=self.category)
with self.assertNumQueries(1): # verified: exactly 1 with select_related("owner")
response = self.client.get("/tools/")
self.assertEqual(response.status_code, 200)
Each test method inside a django.test.TestCase gets its own database transaction, opened before the method runs and rolled back the instant it ends — confirmed directly, by creating five Tool rows in one test's setUp and finding the table empty again at the start of the very next test, with not one line of manual teardown written anywhere. Real inserts, real queries, and still fast, because nothing is ever actually kept. assertNumQueries earns its place here specifically because it's the one assertion standing between chapter six's fix and someone quietly undoing it — delete .select_related("owner") from tool_list a year from now, and the page keeps returning 200, the tool names keep showing up in the response, every assertion that isn't this one stays green, while the query count silently climbs back to nine. self.client.get(...) is doing more than a bare function call to tool_list would: it's routed through URL resolution and the entire middleware chain exactly the way a real browser's request would be, minus an actual server process listening on a port anywhere.