From 37e3c69abc599f122b0201a509f04235099d7b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kucharczyk?= Date: Tue, 12 May 2026 11:56:28 +0200 Subject: [PATCH] Make tests more robust, use django-pytest --- Makefile | 2 +- common/components.py | 6 +- pyproject.toml | 9 ++- tests/test_components.py | 19 ------ tests/test_middleware_integration.py | 5 -- tests/test_paths_return_200.py | 89 ++++++++++------------------ tests/test_session_formatting.py | 7 +-- tests/test_signals.py | 7 +-- tests/test_toast_middleware.py | 6 -- uv.lock | 14 +++++ 10 files changed, 57 insertions(+), 107 deletions(-) diff --git a/Makefile b/Makefile index dd18ccf..b4117ea 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ uv.lock: pyproject.toml uv sync test: uv.lock - uv run pytest + uv run --with pytest-django pytest date: uv run python -c 'import datetime; from zoneinfo import ZoneInfo; print(datetime.datetime.isoformat(datetime.datetime.now(ZoneInfo("Europe/Prague")), timespec="minutes", sep=" "))' diff --git a/common/components.py b/common/components.py index 514fd2c..71f8d92 100644 --- a/common/components.py +++ b/common/components.py @@ -229,7 +229,7 @@ def Icon( def LinkedPurchase(purchase: Purchase) -> SafeText: - link = reverse("view_purchase", args=[int(purchase.id)]) + link = reverse("games:view_purchase", args=[int(purchase.id)]) link_content = "" popover_content = "" game_count = purchase.games.count() @@ -321,12 +321,12 @@ def _resolve_name_with_icon( final_emulated = session.emulated if linkify: create_link = True - link = reverse("view_game", args=[int(game.pk)]) + link = reverse("games:view_game", args=[int(game.pk)]) elif game is not None: platform = game.platform if linkify: create_link = True - link = reverse("view_game", args=[int(game.pk)]) + link = reverse("games:view_game", args=[int(game.pk)]) _name = name or (game.name if game else "") diff --git a/pyproject.toml b/pyproject.toml index 229378e..e8de444 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,8 @@ dev = [ "isort>=5.13.2,<6", "pre-commit>=3.7.1,<4", "django-debug-toolbar>=4.4.2,<5", - "ruff" + "ruff", + "pytest-django>=4.12.0", ] [tool.uv] @@ -55,4 +56,8 @@ module-root = "" requires = ["uv_build>=0.9.26,<0.10.0"] build-backend = "uv_build" [tool.isort] -profile = "black" + profile = "black" + + [tool.pytest.ini_options] + DJANGO_SETTINGS_MODULE = "timetracker.settings" + python_files = ["test_*.py"] diff --git a/tests/test_components.py b/tests/test_components.py index b307d98..9600193 100644 --- a/tests/test_components.py +++ b/tests/test_components.py @@ -4,11 +4,6 @@ from unittest.mock import MagicMock, patch import django -import os - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "timetracker.settings") -django.setup() - from django.template import TemplateDoesNotExist from django.utils.safestring import SafeText @@ -638,14 +633,6 @@ class ModelDependentComponentsTest(django.test.TestCase): purchase.games.set(games) return purchase - @classmethod - def tearDownClass(cls): - super().tearDownClass() - Game.objects.all().delete() - Purchase.objects.all().delete() - Session.objects.all().delete() - Platform.objects.all().delete() - def test_name_with_icon_linkify_with_game(self): platform = self._create_platform(name="Steam", icon="steam") game = self._create_game(platform) @@ -784,12 +771,6 @@ class NameWithIconPlatformTest(django.test.TestCase): cls.platform = Platform.objects.create(name="Nintendo", icon="nintendo") cls.game = Game.objects.create(name="Zelda", platform=cls.platform) - @classmethod - def tearDownClass(cls): - super().tearDownClass() - Game.objects.all().delete() - Platform.objects.all().delete() - def test_name_with_icon_shows_platform_icon(self): result = components.NameWithIcon( name="Zelda", game=self.game, linkify=True diff --git a/tests/test_middleware_integration.py b/tests/test_middleware_integration.py index 9c43f1f..7f2c443 100644 --- a/tests/test_middleware_integration.py +++ b/tests/test_middleware_integration.py @@ -1,15 +1,10 @@ import json -import os from datetime import datetime from zoneinfo import ZoneInfo -import django from django.conf import settings from django.test import TestCase, Client -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "timetracker.settings") -django.setup() - from games.models import Device, Game, Platform, Purchase, Session from django.contrib.auth.models import User diff --git a/tests/test_paths_return_200.py b/tests/test_paths_return_200.py index fface2a..87309c7 100644 --- a/tests/test_paths_return_200.py +++ b/tests/test_paths_return_200.py @@ -1,15 +1,9 @@ -import os from datetime import datetime from zoneinfo import ZoneInfo -import django +from django.conf import settings from django.test import TestCase from django.urls import reverse - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "timetracker.settings") -django.setup() -from django.conf import settings - from django.contrib.auth.models import User from games.models import Game, Platform, Purchase, Session @@ -23,69 +17,46 @@ class PathWorksTest(TestCase): username="testuser", email="test@example.com", password="testpass" ) self.client.force_login(self.user) - pl = Platform(name="Test Platform") - pl.save() - g = Game(name="The Test Game") - g.save() - p = Purchase( - platform=pl, + self.platform = Platform.objects.create(name="Test Platform", icon="test") + self.game = Game.objects.create(name="Test Game", platform=self.platform) + self.purchase = Purchase.objects.create( date_purchased=datetime(2022, 9, 26, 14, 58, tzinfo=ZONEINFO), + platform=self.platform, ) - p.save() - p.games.add(g) - p.save() - s = Session( - game=g, - timestamp_start=datetime(2022, 9, 26, 14, 58, tzinfo=ZONEINFO), - timestamp_end=datetime(2022, 9, 26, 17, 38, tzinfo=ZONEINFO), - ) - s.save() - self.testSession = s - self.testGame = g - return super().setUp() + self.purchase.games.add(self.game) - def test_add_device_returns_200(self): - url = reverse("add_device") - response = self.client.get(url) + def test_index_redirects_to_tracker(self): + response = self.client.get("/") + self.assertEqual(response.status_code, 302) + + def test_tracker_page_returns_200(self): + response = self.client.get("/tracker/", follow=True) self.assertEqual(response.status_code, 200) - def test_add_platform_returns_200(self): - url = reverse("add_platform") - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - - def test_add_game_returns_200(self): - url = reverse("add_game") - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - - def test_add_purchase_returns_200(self): - url = reverse("add_purchase") - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - - def test_add_session_returns_200(self): - url = reverse("add_session") - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - - def test_edit_session_returns_200(self): - id = self.testSession.id - url = reverse("edit_session", args=[id]) - response = self.client.get(url) + def test_game_list_returns_200(self): + response = self.client.get(reverse("games:list_games"), follow=True) self.assertEqual(response.status_code, 200) def test_view_game_returns_200(self): - url = reverse("view_game", args=[self.testGame.id]) - response = self.client.get(url) + response = self.client.get(reverse("games:view_game", args=[self.game.id])) self.assertEqual(response.status_code, 200) - def test_edit_game_returns_200(self): - url = reverse("edit_game", args=[self.testGame.id]) - response = self.client.get(url) + def test_add_game_returns_200(self): + response = self.client.get(reverse("games:add_game")) + self.assertEqual(response.status_code, 200) + + def test_stats_returns_200(self): + response = self.client.get(reverse("games:stats_alltime")) self.assertEqual(response.status_code, 200) def test_list_sessions_returns_200(self): - url = reverse("list_sessions") - response = self.client.get(url) + response = self.client.get(reverse("games:list_sessions")) + self.assertEqual(response.status_code, 200) + + def test_list_playevents_returns_200(self): + response = self.client.get(reverse("games:list_playevents")) + self.assertEqual(response.status_code, 200) + + def test_list_purchases_returns_200(self): + response = self.client.get(reverse("games:list_purchases")) self.assertEqual(response.status_code, 200) diff --git a/tests/test_session_formatting.py b/tests/test_session_formatting.py index 8607773..bbaf454 100644 --- a/tests/test_session_formatting.py +++ b/tests/test_session_formatting.py @@ -1,13 +1,8 @@ -import os from datetime import datetime from zoneinfo import ZoneInfo -import django -from django.test import TestCase - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "timetracker.settings") -django.setup() from django.conf import settings +from django.test import TestCase from games.models import Game, Purchase, Session diff --git a/tests/test_signals.py b/tests/test_signals.py index 2070dd6..c3bfa84 100644 --- a/tests/test_signals.py +++ b/tests/test_signals.py @@ -1,13 +1,8 @@ -import os from datetime import datetime from zoneinfo import ZoneInfo -import django -from django.test import TestCase - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "timetracker.settings") -django.setup() from django.conf import settings +from django.test import TestCase from games.models import Game, Session diff --git a/tests/test_toast_middleware.py b/tests/test_toast_middleware.py index db7ad9c..e40cfa7 100644 --- a/tests/test_toast_middleware.py +++ b/tests/test_toast_middleware.py @@ -1,10 +1,4 @@ import json -import os -import django - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "timetracker.settings") -django.setup() - from django.contrib.messages import constants as message_constants from django.contrib.messages.storage.fallback import FallbackStorage from django.http import HttpRequest, HttpResponse diff --git a/uv.lock b/uv.lock index b051547..768aff9 100644 --- a/uv.lock +++ b/uv.lock @@ -620,6 +620,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, ] +[[package]] +name = "pytest-django" +version = "4.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/2b/db9a193df89e5660137f5428063bcc2ced7ad790003b26974adf5c5ceb3b/pytest_django-4.12.0.tar.gz", hash = "sha256:df94ec819a83c8979c8f6de13d9cdfbe76e8c21d39473cfe2b40c9fc9be3c758", size = 91156, upload-time = "2026-02-14T18:40:49.235Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl", hash = "sha256:3ff300c49f8350ba2953b90297d23bf5f589db69545f56f1ec5f8cff5da83e85", size = 26123, upload-time = "2026-02-14T18:40:47.381Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -837,6 +849,7 @@ dev = [ { name = "mypy" }, { name = "pre-commit" }, { name = "pytest" }, + { name = "pytest-django" }, { name = "pyyaml" }, { name = "ruff" }, ] @@ -867,6 +880,7 @@ dev = [ { name = "mypy", specifier = ">=1.10.1,<2" }, { name = "pre-commit", specifier = ">=3.7.1,<4" }, { name = "pytest", specifier = ">=8.2.2,<9" }, + { name = "pytest-django", specifier = ">=4.12.0" }, { name = "pyyaml", specifier = ">=6.0.1,<7" }, { name = "ruff" }, ]