Partage
  • Partager sur Facebook
  • Partager sur Twitter

Tests unitaires

pour une classe...Et les paramètres ?

    31 juillet 2019 à 9:34:02

    Bonjour, 

    J'ai besoin de faire des tests unitaires. En particulier j'ai besoin que ces tests testent (oulà...:lol:) plusieurs méthodes de ma classe.

    Le problème c'est que ma classe, je ne peux pas l'instancier comme ça, il lui faut des paramètres, et il se trouve que ces paramètres sont relatifs à la connection à un serveur. En plus, à l'initialisation, ma classe a besoin d'éléments fournis par le joueur. Bref.

    Je ne sais pas trop comment faire du coup.

    J'ai cherché, j'ai trouvé des histoires de Mock et de Pacth du module Unittest, mais je ne comprends pas comment ça fonctionne. Je ne sais pas comment je pourrai utiliser ces trucs dans mon code de test, pour pouvoir tester les méthodes de ma classe.

    Quelqu'un sait faire ça ?

    • Partager sur Facebook
    • Partager sur Twitter
      31 juillet 2019 à 9:50:00

      Salut,

      Tu viens de découvrir que ta classe était couplée trop étroitement au reste de ton code. Ca la rend donc difficile à être testée. Ta classe a des dépendances et maintenant que tu as besoin de l'instancier en isolation du reste du code, ça devient évident. C'est une bonne chose. C'est comme ça qu'on progresse dans l'architecture de ses programmes. :) 

      Nous montrer la classe en question nous permettrait de t'aider plus concrètement.

      Comme tu l'as découvert, il est possible d'utilise des mocks afin de remplacer dans le code de ta classe un objet par un simulacre. On peut ensuite demander au mock s'il a été appelé, et si oui avec quelles arguments. Voici un tutoriel pour découvrir son utilisation : https://realpython.com/python-mock-library/

      • Partager sur Facebook
      • Partager sur Twitter
        31 juillet 2019 à 10:03:51

        Il est en anglais le tuto :euh: oui, je sais, il faudrait que je m'y mette, ça devient urgent :-°

        J'ai un peu honte de mon code, je sais que c'est le bordel. Mais bon...ma Classe : 

        # -*-coding:Utf-8 -*
        
        import os
        from random import choice,randint,randrange
        
        
        """Ce module contient la classe Carte. """
        
        class Carte(object):
            """Objet de transition entre un fichier et un labyrinthe.
        Classe qui permet à l'utilisateur de choisir la carte, de l'afficher,
        et de l'enregistrer """
        
            def __init__(self,joueurs_sockets,connectes):
                """Constructeur de la classe"""
                
                self.joueurs = joueurs_sockets
        
                self.path = os.path.abspath("cartes")# enregistre le chemin pour "cartes"
                self.liste_cartes = os.listdir(self.path)
                self.liste_cartes.sort()
                self.maxi = len(self.liste_cartes)
        
                self.lancement(joueurs_sockets,connectes)
        
                
            def lancement(self,joueurs_sockets,connectes) :
                """ Lancement du jeu 'Roboc', composé principalement du choix
        de la carte"""
        
                self.joueurs = joueurs_sockets
                 
                for cartes in self.liste_cartes :
                    env = cartes.encode() + b"\n"
                    connectes.send(env)
                        
                connectes.send(b"L'un de vous doit choisir : \n")
                connectes.send(b"Tapez 0 pour une carte aleatoire\n")
                connectes.send(b"Ou son numero pour choisir l'une des cartes ci-dessus\n")
        
                choix = connectes.recv(5).decode()
        
                while choix != int(choix) :
                    try :
                        choix = int(choix)
                    except ValueError:
                        connectes.send(b"Choix invalide. Tapez 0 ou un numero : ")
                        choix = connectes.recv(5).decode()
        
                        
                while not (0 <= choix <= self.maxi) :
                    connectes.send(b"Choix invalide. Tapez 0 ou un numero : ")
                    choix = connectes.recv(5).decode()
        
                if choix == 0 :
                    self.generation_aleatoire()
                    self.envoi_carte()
                    connectes.send(self.carte)
                    print(self)
                        
                elif choix > 0 and choix <= maxi : 
                    self.nom = self.liste_cartes[choix-1]
                    connectes.send(self.nom.encode())
                    self.chargement()
                    self.envoi_carte()
                    connectes.send(self.carte)
                    print(self)
                
           
        
            def __repr__(self):
                """Ce qui est affiché quand on fait print(self)"""
                return "".join([elt for ligne in self.labyrinthe for elt in ligne])
            
        
            def robot(self) :
                """Place le robot sur la carte, de manière aléatoire"""
                
                cases_vides = []
                lengh = len(self.labyrinthe)
        
                # j'ajoute à une liste les coordonnées de toutes les cases vides :
                for x in range(lengh) :
                    for y in range(lengh) :
                        if self.labyrinthe[x][y] == " " :
                            cases_vides.append((x,y))
        
                # pour chaque joueur enregistré, 
                for sockets,num_joueurs in self.joueurs.items() :
                    (x,y) = choice(cases_vides) # on choisi une case vide au hasard       
                    self.labyrinthe[x][y] = str(num_joueurs) # et on place son robot
        
                
        
                        
        
            def chargement(self) :
                """Récupère la carte choisie par l'utilisateur, et la transfère dans
        une liste des lignes de la carte"""
                with open(Choix_Carte.path +'/'+ Choix_carte.nom,'r') as fichier :
                    self.labyrinthe = []
                    while 1 :
                        ligne = fichier.readline()
                        if ligne == '' :
                            break
                        else :
                            ligne = list(ligne)                                 
                        self.labyrinthe.append(ligne)
                        
                # j'ajoute le robot :
                self.robot()
        
        
            def envoi_carte(self) :
                """Simplement pour afficher la carte à envoyer au joueur. Il s'agit
        seulement d'afficher le labyrinthe"""
                self.carte = '\n' + "".join([elt for ligne in self.labyrinthe for elt in ligne])
                self.carte = self.carte.encode()
        
        
        
            def generation_aleatoire(self) :
                """Génère automatiquement des cartes aléatoires, de 15 caractères
        par 15"""
                elts_laby = [' ','O','.']
                self.labyrinthe = []
        
                # création de 15 listes de symboles aléatoires   
                for _ in range(15):
                    line = []
                    for _ in range(15):
                        line.append(choice(elts_laby))
                    self.labyrinthe.append(line)
        
                for ligne in self.labyrinthe :
                    ligne.append('\n')
        
                # ensuite remplacement des symboles entourant le labyrinthe par
                # des 'o' pour qu'il soit "fermé"
                self.labyrinthe[0] = ['O']*15
                self.labyrinthe[0].append('\n')
        
                self.labyrinthe[14] = ['O']*15
                self.labyrinthe[14].append('\n')
        
                i = 0
                while i <= 14 :
                    self.labyrinthe[i][14] = 'O'
                    self.labyrinthe[i][0] = 'O'
                    i += 1
        
                # + la sortie + le robot : 
                self.labyrinthe[12][14] = 'U'
                self.robot()
        
        
                    
        

        En fait mes méthodes pour charger le labyrinthe, en créer un aléatoire, tout ça....en fait c'est lié au choix de l'utilisateur. Pour ça que je me retrouve coincée. Il faudrait que je trouve comment découper ça en 2. Là j'avoue, je ne sais pas trop. 

        • Partager sur Facebook
        • Partager sur Twitter
          31 juillet 2019 à 10:21:44

          L'anglais est primordial pour faire de la programmation... Toutes les documentations sont en anglais. Tu n'y couperas pas.

          Ta classe souffre de l'erreur classique que j'ai aussi fait à mes débuts. C'est une classe fourre-tout. La classe s'appelle Carte mais c'est en fait tout ton jeu on dirait.

          Il va falloir découper tout ça en plus petit morceaux. Il va falloir déterminer quels objets sont nécessaires pour représenter ton jeu, quels sont leur responsabilité, comment ils interagissent les-uns avec les autres, peut-être un objet contient d'autres objets, etc. Il y a des choses à factoriser -> remplacer par des fonctions. Je vois par exemple du code pour valider l'entrée de l'utilisateur. Ca devrait être une fonction qui s'occupe de cette fonctionnalité. Ainsi on peut tester la fonction en isolation du reste et s'assurer qu'elle valide correctement les entrées qui lui sont données.

          Quand je lis le commentaire "Lancement du jeu 'Roboc', composé principalement du choix de la carte", je me dis qu'il s'agit d'une classe Game, plutôt que Carte. Mais le Jeu doit probablement contenir une Carte. La Carte elle ne doit pas se tracasser de l'input de l'utilisateur. C'est la classe Game qui ferait ça. Il faut juste que Game puisse dire à Carte quelle genre de carte elle doit générer.

          Mes conseils sont évidemment (trop) succincts. Je ne peux pas écrire sur un forum ce qui fait l'objet de tout un cours. :) Donc il faut que tu te documents - hé oui en anglais aussi - et que tu lises du codes d'autres personnes. GitHub est rempli de codes sources. Va voir comment ils séparent les classes et comment elles interagissent.

          Bonne chance pour la suite ! :)

          • Partager sur Facebook
          • Partager sur Twitter
            31 juillet 2019 à 10:37:43

            Merci Dan737 :)

            Je suis en train d'essayer de faire déjà un premier découpage. C'est pas évident du tout :euh: Je vais suivre tes conseils et tenter de travailler tout ça.

            • Partager sur Facebook
            • Partager sur Twitter

            Tests unitaires

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown