Résolue

Test unitaire Django

# Django # JavaScript # Tests unitaires

Bonjour,

J'ai du mal à saisir les test unitaire non pas techniquement mais plutôt dans le sens de son utilisation. (je sais pas si j'ai été claire ^^) Par exemple voici l'une de mes class dans models :

class ProductMeat(models.Model):
    title = models.CharField(max_length=38, unique=True, verbose_name="Viande")
    price = models.FloatField(default=0.0, verbose_name='Prix')
    description = models.TextField(blank=True, verbose_name="Description")
    thumbnail = models.ImageField(upload_to="products", blank=True, null=True, verbose_name='Image produit')
    promo = models.BooleanField(default=False, verbose_name="Produit en promotion")
    percent = models.IntegerField(default=0, verbose_name='Pourcentage promotion')
    promo_date_end = models.DateField(blank=True, null=True, verbose_name='Date fin de promotion')

    class Meta:
        verbose_name = "Viande"

    def __str__(self):
        return self.title

    @property
    def price_with_promotion(self):
        if self.promo:
           return round(self.price - (self.price * self.percent / 100), 2)
        return self.price

Ma class fonctionne très bien dans tous ce que je lui demande mais qu'elle est l'utilité de créé un fichier de test ? Si tout fonctionne... C'est toujours le site pour mon projet d'école et nous devons faire des tests unitaire. J'ai créé un site ou tout ce déroule sur une page grace à du Javascript (cahier des charges) donc pas de test de slug ou url il me reste donc que mes class dans models à testé. Si je peux avoir vos points de vue pour y voir plus claire.

Merci d'avance ^^

Thibault houdon

Mentor

Salut Yann !

Ne t'en fais pas c'est une question légitime que tous les développeurs se posent et que je me souviens m'être également posé pendant longtemps.

Quand on n'a que quelques lignes de code effectivement on peut le tester soi-même et vérifier que tout fonctionne.

Mais même si ton code semble fonctionner parfaitement aujourd'hui, imagine ce qui se passerait si tu devais le modifier demain, ou dans une semaine, ou même dans quelques mois. Peut-être que tu auras oublié comment une certaine fonction fonctionne, ou peut-être qu'un nouvel étudiant travaillera dessus.

Et si une modification casse quelque chose ? Comment peux-tu être au courant ? En testant tout à la main. Mais tu es d'accord pour dire que ça serait un peu long de faire ça à chaque fois. Comme tout en programmation : on souhaite automatiser le maximum. Et c'est à ça que servent les tests unitaires.

Les tests unitaires sont essentiels pour deux raisons principales:

  1. Ils te facilitent la vie : Lorsque tu modifies ou étends ton code, les tests unitaires s'assurent que tu ne casseras rien au passage. Ils vérifient que toutes les parties (unités) de ton code fonctionnent toujours comme prévu. Donc, même si tout fonctionne parfaitement aujourd'hui, c'est une façon d'assurer qu'il en sera de même demain et de le vérifier de façon automatique.

  2. Ils facilitent la vie des autres : Si quelqu'un d'autre reprend ton code (comme cela arrive souvent dans la vraie vie), tes tests unitaires serviront à lui montrer comment le code est censé fonctionner et à vérifier qu'il n'a rien cassé en travaillant dessus.

Dans ton cas, tu peux par exemple écrire un test pour ta méthode price_with_promotion, pour s'assurer qu'elle renvoie toujours le bon montant de réduction, peu importe la valeur de promo ou percent.

Attention cependant : les tests unitaires ne veulent pas dire que ton code fonctionne à 100% et en intégralité. Même si tu as une couverture ("coverage") de 100% de ton code, c'est à dire que chaque petite morceau de ton code est testé, il peut toujours y avoir des choses que tu n'avais pas prévues qui le feront casser.

Il existe même des tests autres que les tests unitaires, par exemple des tests qui vont tester une suite d'interaction, comme si tu te mettais dans la peau d'un utilisateur pour tester ton site.

Je te donne un exemple que j'ai vu passer récemment sur Twitter et qui fait même écho à ton cas d'usage avec la promotion : un dev avait codé une fonctionnalité incluant un prix. Sauf que certains utilisateurs de son site étaient situés sur un autre continent qui utilisait le point au lieu de la virgule pour séparer les centimes. Quand il testait son site de son côté : tout fonctionnait correctement, mais quand il a fait un test unitaire qui a été lancé dans sa suite d'intégration continue, qui se situait sur des serveurs dans un autre continent : le test n'est pas passé à cause de cette différence.

Bref, pour le moment tu peux te contenter de tester ton code et de comprendre techniquement comment fonctionnent les tests sans trop t'en faire avec ça.

Le meilleur moyen de se rendre compte de l'utilité des tests unitaires, c'est de travailler sur des plus gros projets sur lesquels tu vas avoir des bugs régulièrement en changeant ton code. Comme on ne peut pas tout prévoir, tu verras que parfois une toute petite modification dans une fonction peut avoir un effet à l'autre bout de ton site, et les tests permettent de détecter cela.

Merci pour ta réponse, je t'avoue que testé le prix en promotion comme tu me l'as conseillé j'ai pensé que cela serai intuitif a réalisé. Il y a des notions que j'ai du voir dans tes cours ou je n'arrive pas a faire le lien avec ce que j'essaye d'entreprendre. Mon code test commence comme ceci :

class ProductMeatTest(TestCase):
    def test_price_promo(self):
        self.productMeat = ProductMeat.objects.create(
            price="10",
            percent="50",
        )

Et la page blanche ( si je peux le formulé ainsi ) je ne sais pas comment réalisé un test untitaire. ( pourtant j'essaye de beaucoup regardé sur la toile différent tuto etc) mais la choux blanc ! ^^

Thibault houdon

Mentor

Salut Yann !

Tu es sur la bonne piste, tu dois effectivement déjà créer un produit, ensuite il faut tester ta fonction et vérifier qu'elle produit le résultat attendu, comme tu le ferais dans ton code (en utilisant la fonction) et en vérifiant que tout se passe correctement (à la main, mais là le but est d'automatiser tout ça, donc on va utiliser les assertions).

Ta fonction pourrait du coup ressembler à ça :

class ProductMeatTest(TestCase):
    def test_price_promo(self):
        productMeat = ProductMeat.objects.create(
            price=10,
            percent=50,
            promo=True,
        )

        # Maintenant on va vérifier que le prix est bien réduit de 50% 
        self.assertEqual(productMeat.price_with_promotion, 5)

        # On change le pourcentage pour tester un autre cas
        productMeat.percent = 25
        productMeat.save()

        # Vérifie que le prix a bien été réduit de 25%
        self.assertEqual(productMeat.price_with_promotion, 7.5)

        # Teste un cas où la promotion n'est pas activée
        productMeat.promo = False
        productMeat.save()

        # Le prix ne devrait pas être réduit si 'promo' est False
        self.assertEqual(productMeat.price_with_promotion, 10)

Ici, je crée un produit Meat avec un prix initial de 10$ et une promotion de 50%. Ensuite, j'utilise la fonction assertEqual de Django pour vérifier que le prix avec la promotion est bien de 5$.

Tu peux utiliser cette fonction assertEqual pour comparer le résultat de ta fonction price_with_promotion à la valeur que tu t'attends à obtenir.

Ensuite, je change la valeur de percent à 25 et je vérifie que le prix est bien réduit de 25%. Et pour finir, je teste un cas où la promotion n'est pas activée en mettant promo à False, et je vérifie que le prix n'est pas réduit.

Ce n'est qu'un exemple et selon les cas que tu veux couvrir tu peux adapter, mais j'espère que ça t'aidera à mieux comprendre comment écrire tes tests unitaires.

Et du coup imagine que quelqu'un modifie ta fonction par la suite et décide que le prix doit être réduit même si promo est False. Dans ce cas ton test le détectera car le dernier assertEqual ne sera plus valide (ton prix sera réduit et ne sera donc plus égal à 10).

Dans ce cas-là deux possibilités :

  • 1) C'est vraiment ce que tu / ton équipe souhaite : dans ce cas tu modifie ton test pour qu'il prenne en compte cette modification dans ton code.

  • 2) Ton ami qui a modifié la fonction a fait une erreur et le prix ne devrait pas être réduit : tu peux rejeter le code avant le déploiement pour t'assurer qu'il fonctionne comme prévu.

Dans le 2e cas de figure, le test unitaire, qui roule normalement avant le déploiement de ton application, aura prévenu un problème en production :)

J'espère que tu y vois plus clair :)

P.S : je vois que tu passes de chaînes de caractères pour le prix et la réduction, tu devrais utiliser des nombres plutôt.

Merci j'y vois un peu plus claire, ce qui était flou pour moi et ou je n'arrivais pas trouver d'exemple c'etait comment appeler une fonction de ma class. Je ne savais pas comment rédiger mon code. Donc dans les assertions on peu appelé n'importe qu'elle fonction d'une class. Les tests unitaire que j'ai vu c'était toujours des comparaisons de variable. TOP

Merci encore pour cette petite lecon ^^ Très bon weekend à toi !

Inscris-toi

(c'est gratuit !)

Inscris-toi

Tu dois créer un compte pour participer aux discussions.

Créer un compte

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.