faster tests

This commit is contained in:
thomas girod 2024-07-04 10:19:24 +02:00
parent 47fec973bc
commit aa07fa9207
11 changed files with 75 additions and 49 deletions

View File

@ -6,7 +6,7 @@ from django.utils.translation import activate
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def django_db_setup(django_db_setup, django_db_blocker): def django_db_setup(django_db_setup, django_db_blocker):
with django_db_blocker.unblock(): with django_db_blocker.unblock():
call_command("setup") call_command("populate")
@pytest.fixture(scope="session", autouse=True) @pytest.fixture(scope="session", autouse=True)

View File

@ -1098,8 +1098,10 @@ Welcome to the wiki page!
n = News( n = News(
title="Repas barman", title="Repas barman",
summary="Enjoy la fin du semestre!", summary="Enjoy la fin du semestre!",
content="Viens donc t'enjailler avec les autres barmans aux " content=(
"frais du BdF! \o/", "Viens donc t'enjailler avec les autres barmans aux "
"frais du BdF! \\o/"
),
type="EVENT", type="EVENT",
club=bar_club, club=bar_club,
author=subscriber, author=subscriber,

View File

@ -19,7 +19,8 @@ import base64
import os import os
import random import random
import string import string
from datetime import date, datetime, timedelta, timezone from datetime import date, datetime, timedelta
from datetime import timezone as tz
from typing import Tuple from typing import Tuple
from dict2xml import dict2xml from dict2xml import dict2xml
@ -549,7 +550,7 @@ class Counter(models.Model):
if since is None: if since is None:
since = get_start_of_semester() since = get_start_of_semester()
if isinstance(since, date): if isinstance(since, date):
since = datetime(since.year, since.month, since.day, tzinfo=timezone.utc) since = datetime(since.year, since.month, since.day, tzinfo=tz.utc)
return ( return (
self.sellings.filter(date__gte=since) self.sellings.filter(date__gte=since)
.annotate( .annotate(
@ -583,7 +584,7 @@ class Counter(models.Model):
if since is None: if since is None:
since = get_start_of_semester() since = get_start_of_semester()
if isinstance(since, date): if isinstance(since, date):
since = datetime(since.year, since.month, since.day, tzinfo=timezone.utc) since = datetime(since.year, since.month, since.day, tzinfo=tz.utc)
total = self.sellings.filter(date__gte=since).aggregate( total = self.sellings.filter(date__gte=since).aggregate(
total=Sum(F("quantity") * F("unit_price"), output_field=CurrencyField()) total=Sum(F("quantity") * F("unit_price"), output_field=CurrencyField())
)["total"] )["total"]

View File

@ -207,6 +207,29 @@ Pour lancer les tests il suffit d'utiliser la commande intégrée à django.
# Lancer une méthode en particulier de cette même classe # Lancer une méthode en particulier de cette même classe
pytest core.tests.UserRegistrationTest.test_register_user_form_ok pytest core.tests.UserRegistrationTest.test_register_user_form_ok
.. note::
Certains tests sont un peu longs à tourner.
Pour ne faire tourner que les tests les plus rapides,
vous pouvez exécutez pytest ainsi :
.. code-block:: bash
pytest -m "not slow"
# vous pouvez toujours faire comme au-dessus
pytest core -m "not slow"
A l'inverse, vous pouvez ne faire tourner que les tests
lents en remplaçant `-m "not slow"` par `-m slow`.
De cette manière, votre processus de développement
devrait être un peu plus fluide.
Cependant, n'oubliez pas de bien faire tourner
tous les tests avant de push un commit.
Vérifier les dépendances Javascript Vérifier les dépendances Javascript
----------------------------------- -----------------------------------

View File

@ -220,10 +220,11 @@ class EbouticTest(TestCase):
self.client.get(reverse("eboutic:command")) self.client.get(reverse("eboutic:command"))
response = self.client.get(et_answer_url) response = self.client.get(et_answer_url)
assert response.status_code == 500 assert response.status_code == 500
assert ( msg = (
"Basket processing failed with error: SuspiciousOperation('Basket total and amount do not match'" "Basket processing failed with error: "
in response.content.decode("utf-8"), "SuspiciousOperation('Basket total and amount do not match'"
) )
assert msg in response.content.decode("utf-8")
def test_buy_simple_product_with_credit_card(self): def test_buy_simple_product_with_credit_card(self):
self.client.force_login(self.subscriber) self.client.force_login(self.subscriber)

View File

@ -147,20 +147,20 @@ class Command(BaseCommand):
self.logger.info(f"Creating {u}") self.logger.info(f"Creating {u}")
self.users.append(u) self.users.append(u)
User.objects.bulk_create(self.users) User.objects.bulk_create(self.users)
self.users = User.objects.filter(username__startswith="galaxy-").all() self.users = list(User.objects.filter(username__startswith="galaxy-").all())
# now that users are created, create their subscription # now that users are created, create their subscription
subs = [] subs = []
for i in range(self.NB_USERS): end = Subscription.compute_end(duration=2)
u = self.users[i] for i, user in enumerate(self.users):
self.logger.info(f"Registering {u}") self.logger.info(f"Registering {user}")
subs.append( subs.append(
Subscription( Subscription(
member=u, member=user,
subscription_start=Subscription.compute_start( subscription_start=Subscription.compute_start(
self.now - timedelta(days=self.NB_USERS - i) self.now - timedelta(days=self.NB_USERS - i)
), ),
subscription_end=Subscription.compute_end(duration=2), subscription_end=end,
) )
) )
Subscription.objects.bulk_create(subs) Subscription.objects.bulk_create(subs)
@ -381,28 +381,15 @@ class Command(BaseCommand):
u1.godchildren.add(u3) u1.godchildren.add(u3)
self.logger.info(f"{u1} will be important and close to {u2} and {u3}") self.logger.info(f"{u1} will be important and close to {u2} and {u3}")
pictures_tags = [] pictures_tags = []
for p in range( # Mix them with other citizen for more chaos for p in range(uid - 400, uid - 200):
uid - 400, uid - 200 # Mix them with other citizen for more chaos
): pictures_tags += [
# users may already be on the pictures PeoplePictureRelation(user=u1, picture=self.picts[p]),
if not self.picts[p].people.filter(user=u1).exists(): PeoplePictureRelation(user=u2, picture=self.picts[p]),
pictures_tags.append( PeoplePictureRelation(user=u1, picture=self.picts[p + self.NB_USERS]),
PeoplePictureRelation(user=u1, picture=self.picts[p]) PeoplePictureRelation(user=u2, picture=self.picts[p + self.NB_USERS]),
) ]
if not self.picts[p].people.filter(user=u2).exists(): # users may already be on the pictures.
pictures_tags.append( # In this case the conflict will just be ignored
PeoplePictureRelation(user=u2, picture=self.picts[p]) # and nothing will happen for this entry
) PeoplePictureRelation.objects.bulk_create(pictures_tags, ignore_conflicts=True)
if not self.picts[p + self.NB_USERS].people.filter(user=u1).exists():
pictures_tags.append(
PeoplePictureRelation(
user=u1, picture=self.picts[p + self.NB_USERS]
)
)
if not self.picts[p + self.NB_USERS].people.filter(user=u2).exists():
pictures_tags.append(
PeoplePictureRelation(
user=u2, picture=self.picts[p + self.NB_USERS]
)
)
PeoplePictureRelation.objects.bulk_create(pictures_tags)

View File

@ -25,6 +25,7 @@
import json import json
from pathlib import Path from pathlib import Path
import pytest
from django.core.management import call_command from django.core.management import call_command
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
@ -147,6 +148,7 @@ class GalaxyTestModel(TestCase):
galaxy.rule(0) # We want everybody here galaxy.rule(0) # We want everybody here
@pytest.mark.slow
class GalaxyTestView(TestCase): class GalaxyTestView(TestCase):
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
@ -196,6 +198,4 @@ class GalaxyTestView(TestCase):
# Dump computed state, either for easier debugging, or to copy as new reference if changes are legit # Dump computed state, either for easier debugging, or to copy as new reference if changes are legit
(galaxy_dir / "test_galaxy_state.json").write_text(json.dumps(state)) (galaxy_dir / "test_galaxy_state.json").write_text(json.dumps(state))
assert ( assert state == json.loads((galaxy_dir / "ref_galaxy_state.json").read_text())
state == json.loads((galaxy_dir / "ref_galaxy_state.json").read_text()),
)

10
poetry.lock generated
View File

@ -573,17 +573,17 @@ test = ["testfixtures"]
[[package]] [[package]]
name = "djangorestframework" name = "djangorestframework"
version = "3.15.1" version = "3.15.2"
description = "Web APIs for Django, made easy." description = "Web APIs for Django, made easy."
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.8"
files = [ files = [
{file = "djangorestframework-3.15.1-py3-none-any.whl", hash = "sha256:3ccc0475bce968608cf30d07fb17d8e52d1d7fc8bfe779c905463200750cbca6"}, {file = "djangorestframework-3.15.2-py3-none-any.whl", hash = "sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20"},
{file = "djangorestframework-3.15.1.tar.gz", hash = "sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1"}, {file = "djangorestframework-3.15.2.tar.gz", hash = "sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad"},
] ]
[package.dependencies] [package.dependencies]
django = ">=3.0" django = ">=4.2"
[[package]] [[package]]
name = "docutils" name = "docutils"

View File

@ -76,6 +76,7 @@ select = ["I", "F401"]
[tool.pytest.ini_options] [tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "sith.settings" DJANGO_SETTINGS_MODULE = "sith.settings"
python_files = ["tests.py", "test_*.py", "*_tests.py"] python_files = ["tests.py", "test_*.py", "*_tests.py"]
markers = ["slow"]
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]

View File

@ -72,7 +72,7 @@ class MergeUserTest(TestCase):
assert "B'ian" == self.to_keep.nick_name assert "B'ian" == self.to_keep.nick_name
assert "Jerusalem" == self.to_keep.address assert "Jerusalem" == self.to_keep.address
assert "Rome" == self.to_keep.parent_address assert "Rome" == self.to_keep.parent_address
assert (3, self.to_keep.groups.count()) assert self.to_keep.groups.count() == 3
groups = sorted(self.to_keep.groups.all(), key=lambda i: i.id) groups = sorted(self.to_keep.groups.all(), key=lambda i: i.id)
expected = sorted([subscribers, mde_admin, sas_admin], key=lambda i: i.id) expected = sorted([subscribers, mde_admin, sas_admin], key=lambda i: i.id)
assert groups == expected assert groups == expected

View File

@ -696,6 +696,17 @@ if DEBUG:
if TESTING: if TESTING:
CAPTCHA_TEST_MODE = True CAPTCHA_TEST_MODE = True
PASSWORD_HASHERS = [ # not secure, but faster password hasher
"django.contrib.auth.hashers.MD5PasswordHasher",
]
STORAGES = { # store files in memory rather than using the hard drive
"default": {
"BACKEND": "django.core.files.storage.InMemoryStorage",
},
"staticfiles": {
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
},
}
if SENTRY_DSN: if SENTRY_DSN:
# Connection to sentry # Connection to sentry