Django TestCase : modelformset
Bonsoir ! :)
J'ai une vue et un formulaire, et je m'en sers pour un modelformset. Avec une méthode POST je passe à True le champ validation.
ça fonctionne bien.
Mais je n'arrive pas à le tester.
Du coup j'ai effacé tout ce que j'ai essayé de faire et je vais repartir de 0 pour ce test.
Je ne sais pas s'il y a moyen de passer une instance de Order, et de tester ensuite si validation est True.
Merci d'avance :)
# Vue
@user_passes_test(lambda user: user.is_superuser)
def admin_deal_validation_view(request):
pending_orders = Order.objects.filter(validation=False, ordered=True)
PendingFormSet = modelformset_factory(Order, PendingForm, extra=0)
formset = PendingFormSet(queryset=pending_orders)
if request.method == "POST":
formset = PendingFormSet(request.POST, queryset=pending_orders)
if formset.is_valid():
formset.save()
return HttpResponseRedirect(request.path)
return render(request, "shop/admin-validation.html", context={"forms": formset})
# Formulaire
class PendingForm(forms.ModelForm):
class Meta:
model = Order
fields = ["validation"]
Salut Gab !
Tu as le code de ton test que tu as essayé et qui ne fonctionne pas ?
Effectivement là tu semble ne pas cibler un Order spécifique mais juste tous les Order qui ne sont pas validés et qui ont été "ordered".
Dans ton test tu peux créer des ordres validés et d'autres non validés, tester ta vue, et vérifier ensuite que ceux qui n'étaient pas validés le sont.
Ah mince j'ai tout effacé.
Mais j'étais parti sur le même modèle que le docbot car là vraiment j'étais bloqué.
Je n'ai qu'un champ
class MaVueTest(TestCase):
def test_mon_formset_view(self):
formset_data = {
'form-TOTAL_FORMS': '1',
'form-INITIAL_FORMS': '0',
'form-MAX_NUM_FORMS': '',
# Ici, nous supposons que 'mon_champ' est un BooleanField sur le formulaire.
# Nous voulons soumettre le formset comme si la case avait été coché (True).
'form-0-validation': 'on', # Normalement, les champs de type checkbox sont soumis avec la valeur 'on' si cochés.
}
Je voualais passer une instance du setUp pour vérifier que validation est True avec assertTrue.
Mais je n'ai pas réussi.
Ok alors en premier tu vas devoir créer une instance de Order dans ta base de test pour pouvoir l'utiliser dans ton test.
Tu peux le faire dans la méthode setUp de ta classe de test effectivement c'est une bonne idée.
Par la suite tu peux faire un POST avec ton formset_data.
from django.test import TestCase
from django.urls import reverse
from .models import Order
from .forms import PendingForm
class MaVueTest(TestCase):
def setUp(self):
# Créer des instances pour les tests
self.order = Order.objects.create(validation=False, ordered=True)
# Si tu as besoin de simuler un utilisateur superuser
self.superuser = User.objects.create_superuser('admin', '[email protected]', 'pass')
self.client.login(username='admin', password='pass')
def test_mon_formset_view_valid(self):
formset_data = {
'form-TOTAL_FORMS': '1',
'form-INITIAL_FORMS': '0',
'form-MAX_NUM_FORMS': '',
'form-0-id': self.order.id, # 👉 Il faut spécifier l'ID de l'instance que tu veux modifier
'form-0-validation': 'on', # On coche la case
}
# Ici on suppose que l'url de ta vue est 'admin_deal_validation' mais change le pour ta vraie URL
url = reverse('admin_deal_validation')
# On se connecte en tant que superuser (si ta vue exige un superuser)
self.client.force_login(self.superuser)
response = self.client.post(url, formset_data)
# Vérifie que la réponse est bien une redirection (code 302)
self.assertEqual(response.status_code, 302)
# Reload l'entité depuis la db et vérifie que ça a été sauvé
self.order.refresh_from_db()
# Vérifie que l'attribut 'validation' de l'instance est maintenant à True
self.assertTrue(self.order.validation)
def test_mon_formset_view_invalid(self):
# Pour un test vraiment complet tu pourrais rajouter ici un test avec des données invalides pour vérifier que tout fonctionne bien.
...
Quand tu fais un test avec un formset, tu dois t'assurer de passer les bonnes données pour le management form (form-TOTAL_FORMS, form-INITIAL_FORMS, form-MAX_NUM_FORMS) et aussi l'ID de chaque instance de Order que tu veux modifier.
Merci Thibault !
Je ne dois pas être loin mais :
django.db.utils.IntegrityError: NOT NULL constraint failed: shop_order.user_id
J'ai bien un utilisateur rattaché pourtant...
Tu as déjà eu le cas ?
def test_admin_deal_validation_if_superuser_post(self):
self.client.force_login(self.superuser1)
formset_data = {
'form-TOTAL_FORMS': '1',
'form-INITIAL_FORMS': '0',
'form-MAX_NUM_FORMS': '',
'form-0-id': self.order_user1.id,
'form-0-validation': 'on',
}
print(self.order_user1.validation)
response = self.client.post(reverse("shop:admin-validation"), formset_data)
self.assertEqual(response.status_code, 200)
self.order_user1.refresh_from_db()
print(self.order_user1.validation)
self.assertTrue(self.order_user1.validation)
je crois que c'est le test le plus compliqué. Tout le reste j'ai quasiment réussi à tout gérer.
Ça dépend ce que tu as mis dans ton setUp en fait, dans mon code je n'avais pas mis d'utilisateur n'ayant pas eu le modèle sous les yeux.
ici :
self.order = Order.objects.create(validation=False, ordered=True)
Du coup si tu as un champ qui requiert un utilisateur dans ton modèle Order et que tu n'en donnes pas ça te donne l'erreur que tu as.
Je l'avais mis l'user dans le setUp.
Version simplifiée (car j'ai un méga setUp lol) :
def setUp(self):
self.user1 = ExChanger.objects.create_user(email="[email protected]", username="test_gabigab", first_name="Trouvé",
last_name="Gabriel", password="12345678", foot_size=42,
favorite_color=self.color1, type="h")
self.order_user1: Order = Order.objects.create(user=self.user1, garment=self.garment_to_order_user1,
ordered=True, ordered_date=timezone.now())
def test_admin_deal_validation_if_superuser_post(self):
self.client.force_login(self.superuser1)
formset_data = {
'form-TOTAL_FORMS': '1',
'form-INITIAL_FORMS': '0',
'form-MAX_NUM_FORMS': '',
'form-0-id': self.order_user1.id,
'form-0-validation': 'on',
}
print(self.order_user1.validation)
response = self.client.post(reverse("shop:admin-validation"), formset_data)
self.assertEqual(response.status_code, 200)
self.order_user1.refresh_from_db()
print(self.order_user1.validation)
self.assertTrue(self.order_user1.validation)
Au pire ça peut attendre que tu ais cloné le repo c'est sur le projet du mois.
Tu veux que je clôture pour le moment ? Car j'avoue que comme ça c'est pas simple, j'ai un gros setUp de 50 lignes en plus... lol
Inscris-toi
(c'est gratuit !)
Tu dois créer un compte pour participer aux discussions.
Créer un compte