From 473e5f319b86250e7778de08028699cb65a66256 Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Sun, 25 Jan 2026 18:00:42 +0100 Subject: [PATCH 1/8] Add pytest config for django and pyproject - Add python file pattern and python path to pyproject.toml. - Specify pytest as Django's testrunner for './manage.py test' support --- pyproject.toml | 2 ++ src/bornhack/settings.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 1a63bd5fc..52beebabd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -181,3 +181,5 @@ exclude_also = [ ############ PYTEST ############ [tool.pytest.ini_options] DJANGO_SETTINGS_MODULE = "bornhack.settings" +python_files = "tests.py test_*.py" +pythonpath = ". src" diff --git a/src/bornhack/settings.py b/src/bornhack/settings.py index 35007dec3..88623addc 100644 --- a/src/bornhack/settings.py +++ b/src/bornhack/settings.py @@ -288,3 +288,6 @@ "LOCATION": "tile-cache", }, } + +# Use pytest as test runner for integrating with `./manage.py test` +TEST_RUNNER = "pytest_django.runner.TestRunner" From 53a9ad95b138e90a410d79c02496732f5d17c9d8 Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Sun, 25 Jan 2026 18:07:09 +0100 Subject: [PATCH 2/8] Fix tests failing when run from rootdir - Rename and change type for existing 'FIXTURE_DIRS' from list to Path. - Use new Path object for opening testdata in economy tests. --- src/bornhack/settings.py | 2 +- src/economy/tests.py | 39 ++++++++++++++++++++------------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/bornhack/settings.py b/src/bornhack/settings.py index 88623addc..d557f09d5 100644 --- a/src/bornhack/settings.py +++ b/src/bornhack/settings.py @@ -280,7 +280,7 @@ "tasker": "Team Tasker - task management", } -FIXTURE_DIRS = ["testdata"] +FIXTURE_DIR = BASE_DIR / "testdata" CACHES = { "default": { diff --git a/src/economy/tests.py b/src/economy/tests.py index 9af5cd210..04fd622f2 100644 --- a/src/economy/tests.py +++ b/src/economy/tests.py @@ -5,6 +5,7 @@ from django.core.exceptions import ValidationError from django.test import TestCase from django.utils import timezone +from django.conf import settings from .models import Bank from .models import BankAccount @@ -30,13 +31,13 @@ def test_bank_account_csv_import(self): ) # make sure we create 6 transactions - with open("testdata/bank.csv", encoding="utf-8-sig") as f: + with open(settings.FIXTURE_DIR / "bank.csv", encoding="utf-8-sig") as f: reader = csv.reader(f, delimiter=";", quotechar='"') created = account.import_csv(reader) self.assertEqual(created, 6) # make sure we create 0 if we load the same file again - with open("testdata/bank.csv", encoding="utf-8-sig") as f: + with open(settings.FIXTURE_DIR / "bank.csv", encoding="utf-8-sig") as f: reader = csv.reader(f, delimiter=";", quotechar='"') created = account.import_csv(reader) self.assertEqual(created, 0) @@ -49,7 +50,7 @@ def test_bank_account_csv_import(self): ValidationError, msg="Transaction on 2021-09-01 is before the bank accounts start_date. Transaction text is 'c051c94d-0762-422b-a453-e14402' and amount is -250.00", ): - with open("testdata/bank.csv", encoding="utf-8-sig") as f: + with open(settings.FIXTURE_DIR / "bank.csv", encoding="utf-8-sig") as f: reader = csv.reader(f, delimiter=";", quotechar='"') created = account.import_csv(reader) @@ -58,7 +59,7 @@ class CoinifyCSVImportTest(TestCase): def test_coinify_invoice_csv_import(self): # make sure we create 4 invoices with open( - "testdata/coinify-invoices-20200101-20200630.csv", + settings.FIXTURE_DIR / "coinify-invoices-20200101-20200630.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=",", quotechar='"') @@ -67,7 +68,7 @@ def test_coinify_invoice_csv_import(self): # make sure we create 0 invoices if the same csv is imported again with open( - "testdata/coinify-invoices-20200101-20200630.csv", + settings.FIXTURE_DIR / "coinify-invoices-20200101-20200630.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=",", quotechar='"') @@ -77,7 +78,7 @@ def test_coinify_invoice_csv_import(self): def test_coinify_payout_csv_import(self): # make sure we create 2 payouts with open( - "testdata/coinify-payouts-20210701-20210904.csv", + settings.FIXTURE_DIR / "coinify-payouts-20210701-20210904.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=",", quotechar='"') @@ -86,7 +87,7 @@ def test_coinify_payout_csv_import(self): # make sure we create 0 payouts if the same csv is imported again with open( - "testdata/coinify-payouts-20210701-20210904.csv", + settings.FIXTURE_DIR / "coinify-payouts-20210701-20210904.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=",", quotechar='"') @@ -96,7 +97,7 @@ def test_coinify_payout_csv_import(self): def test_coinify_balance_csv_import(self): # make sure we create 66 balances with open( - "testdata/coinify-account-balances-20210701-20210904.csv", + settings.FIXTURE_DIR / "coinify-account-balances-20210701-20210904.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=",", quotechar='"') @@ -105,7 +106,7 @@ def test_coinify_balance_csv_import(self): # make sure we create 0 balances if the same csv is imported again with open( - "testdata/coinify-account-balances-20210701-20210904.csv", + settings.FIXTURE_DIR / "coinify-account-balances-20210701-20210904.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=",", quotechar='"') @@ -116,13 +117,13 @@ def test_coinify_balance_csv_import(self): class EpayCSVImportTest(TestCase): def test_epay_csv_import(self): # make sure we create 4 epay transactions - with open("testdata/epay_test.csv", encoding="utf-8-sig") as f: + with open(settings.FIXTURE_DIR / "epay_test.csv", encoding="utf-8-sig") as f: reader = csv.reader(f, delimiter=";", quotechar='"') created = import_epay_csv(reader) self.assertEqual(created, 3) # make sure we create 0 if the same csv is imported again - with open("testdata/epay_test.csv", encoding="utf-8-sig") as f: + with open(settings.FIXTURE_DIR / "epay_test.csv", encoding="utf-8-sig") as f: reader = csv.reader(f, delimiter=";", quotechar='"') created = import_epay_csv(reader) self.assertEqual(created, 0) @@ -131,13 +132,13 @@ def test_epay_csv_import(self): class ClearhausCSVImportTest(TestCase): def test_clearhaus_csv_import(self): # make sure we create 10 clearhaus settlements - with open("testdata/clearhaus_settlements.csv", encoding="utf-8-sig") as f: + with open(settings.FIXTURE_DIR / "clearhaus_settlements.csv", encoding="utf-8-sig") as f: reader = csv.reader(f, delimiter=",", quotechar='"') created = import_clearhaus_csv(reader) self.assertEqual(created, 9) # make sure we create 0 if the same csv is imported again - with open("testdata/clearhaus_settlements.csv", encoding="utf-8-sig") as f: + with open(settings.FIXTURE_DIR / "clearhaus_settlements.csv", encoding="utf-8-sig") as f: reader = csv.reader(f, delimiter=",", quotechar='"') created = import_clearhaus_csv(reader) self.assertEqual(created, 0) @@ -145,7 +146,7 @@ def test_clearhaus_csv_import(self): class ZettleImportTest(TestCase): def test_zettle_receipts_import(self): - with open("testdata/Zettle-Receipts-Report-20210101-20210910.xlsx", "rb") as f: + with open(settings.FIXTURE_DIR / "Zettle-Receipts-Report-20210101-20210910.xlsx", "rb") as f: df = ZettleExcelImporter.load_zettle_receipts_excel(f) created = ZettleExcelImporter.import_zettle_receipts_df(df) self.assertEqual(created, 6) @@ -154,7 +155,7 @@ def test_zettle_receipts_import(self): self.assertEqual(created, 0) def test_zettle_balances_import(self): - with open("testdata/Zettle-Account-Statement-Report-20230901-20250903.xlsx", "rb") as f: + with open(settings.FIXTURE_DIR / "Zettle-Account-Statement-Report-20230901-20250903.xlsx", "rb") as f: df = ZettleExcelImporter.load_zettle_balances_excel(f) created = ZettleExcelImporter.import_zettle_balances_df(df) self.assertEqual(created, 4059) @@ -166,7 +167,7 @@ def test_zettle_balances_import(self): class MobilePayImportTest(TestCase): def test_mobilepay_import(self): with open( - "testdata/MobilePay_Transfer_overview_csv_MyShop_25-08-2021_14-09-2021.csv", + settings.FIXTURE_DIR / "MobilePay_Transfer_overview_csv_MyShop_25-08-2021_14-09-2021.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=";", quotechar='"') @@ -175,7 +176,7 @@ def test_mobilepay_import(self): # make sure we create 0 if the same csv is imported again with open( - "testdata/MobilePay_Transfer_overview_csv_MyShop_25-08-2021_14-09-2021.csv", + settings.FIXTURE_DIR / "MobilePay_Transfer_overview_csv_MyShop_25-08-2021_14-09-2021.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=";", quotechar='"') @@ -184,7 +185,7 @@ def test_mobilepay_import(self): # now test importing sales CSV, 3 out of 4 lines are already in from above import with open( - "testdata/MobilePay_Sales_overview_csv_MyShop_25-08-2021_14-09-2021.csv", + settings.FIXTURE_DIR / "MobilePay_Sales_overview_csv_MyShop_25-08-2021_14-09-2021.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=";", quotechar='"') @@ -197,7 +198,7 @@ def test_mobilepay_import(self): ) # make sure we create 0 if the same csv is imported again with open( - "testdata/MobilePay_Sales_overview_csv_MyShop_25-08-2021_14-09-2021.csv", + settings.FIXTURE_DIR / "MobilePay_Sales_overview_csv_MyShop_25-08-2021_14-09-2021.csv", encoding="utf-8-sig", ) as f: reader = csv.reader(f, delimiter=";", quotechar='"') From b4b1164701bd2e08fb609dcb5ee917af62f06c1f Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Sun, 25 Jan 2026 18:16:24 +0100 Subject: [PATCH 3/8] Add pytest pkgs to pyproject and remove ruff ignore --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 52beebabd..1685d017b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,7 @@ dev = [ test = [ "bornhack-website[bootstrap]", + "pytest-django==4.11.1", "beautifulsoup4==4.14.3", "coverage==7.13.0", "hypothesis==6.150.3", @@ -113,7 +114,6 @@ ignore = [ "ARG002", # Unused method argument "EM101", # Exception must not use a string literal, assign to variable first "EM102", # Exception must not use a f-string literal, assign to variable first - "PT", # We use django tests, not pytest ] [tool.ruff.lint.per-file-ignores] From f089eaab464937646f3bcd9656b24b7ae1f915ed Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Sun, 25 Jan 2026 18:17:27 +0100 Subject: [PATCH 4/8] Fixup: Previous commit --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 1685d017b..772b72805 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,7 @@ dev = [ test = [ "bornhack-website[bootstrap]", + "pytest==9.0.2", "pytest-django==4.11.1", "beautifulsoup4==4.14.3", "coverage==7.13.0", From 4bf9ee1aefe397ea3df76c0ee3858e73a8e0449b Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Sun, 25 Jan 2026 19:58:42 +0100 Subject: [PATCH 5/8] Fix failing CI test execution. - Adding pytest-xdist for parallel test execution. - Removing 'cd src' as src is defined as a pythonpath in pyproject.toml --- .github/workflows/main.yml | 3 +-- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b0b0c3ee9..657030f56 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,8 +56,7 @@ jobs: - name: "Run tests" run: | - cd src - coverage run --rcfile ../pyproject.toml manage.py test . --noinput --parallel=4 + coverage run --rcfile ../pyproject.toml pytest -n auto coverage xml --rcfile ../pyproject.toml env: POSTGRES_HOST: "localhost" diff --git a/pyproject.toml b/pyproject.toml index 772b72805..50d03d839 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,7 @@ dev = [ test = [ "bornhack-website[bootstrap]", "pytest==9.0.2", + "pytest-xdist==3.8.0", "pytest-django==4.11.1", "beautifulsoup4==4.14.3", "coverage==7.13.0", From b90c68d522118fb6832971303c76d32e52ae5bef Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Sun, 25 Jan 2026 20:02:14 +0100 Subject: [PATCH 6/8] Fix wrong path for 'pyproject.toml' --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 657030f56..42c56db36 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,8 +56,8 @@ jobs: - name: "Run tests" run: | - coverage run --rcfile ../pyproject.toml pytest -n auto - coverage xml --rcfile ../pyproject.toml + coverage run --rcfile ./pyproject.toml pytest -n auto + coverage xml --rcfile ./pyproject.toml env: POSTGRES_HOST: "localhost" POSTGRES_PORT: 5432 From bdde9ec6a5ea50acf9a589cd2dd6145b5a955de3 Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Sun, 25 Jan 2026 20:07:47 +0100 Subject: [PATCH 7/8] Use python to execute pytest --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 42c56db36..44ffef33c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,7 +56,7 @@ jobs: - name: "Run tests" run: | - coverage run --rcfile ./pyproject.toml pytest -n auto + coverage run --rcfile ./pyproject.toml python -m pytest -n auto coverage xml --rcfile ./pyproject.toml env: POSTGRES_HOST: "localhost" From bc3b46b3a5c312b637069e70abcf9ac77fca9ee8 Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Sun, 25 Jan 2026 20:14:39 +0100 Subject: [PATCH 8/8] Read the friendly manual --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 44ffef33c..a34357b91 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,7 +56,7 @@ jobs: - name: "Run tests" run: | - coverage run --rcfile ./pyproject.toml python -m pytest -n auto + coverage run --rcfile ./pyproject.toml -m pytest -n auto coverage xml --rcfile ./pyproject.toml env: POSTGRES_HOST: "localhost"