Maison > développement back-end > Tutoriel Python > Classes Python moqueuses

Classes Python moqueuses

王林
Libérer: 2024-08-28 18:32:30
original
407 Les gens l'ont consulté

Mocking Python Classes

Dernièrement, j'ai dû écrire des tests unitaires en utilisant Pytest pour un module Python. Le module contient une classe où d'autres classes sont initialisées au sein de son constructeur.

Comme d'habitude, j'ai créé un dispositif pour cette classe afin de faciliter l'écriture d'un test pour chaque méthode de classe. À ce stade, j'ai rencontré quelques problèmes lorsque j'ai essayé de me moquer des différentes classes initiées dans le constructeur. Les moqueries n'ont pas fonctionné et des instances de ces classes étaient toujours en cours de création.

Après quelques recherches et en combinant quelques solutions différentes que j'ai trouvées en ligne, je souhaite partager comment j'ai réussi à me moquer des cours.

Solution

Voici un exemple de la classe dont j'ai essayé de me moquer :

class ClassA:
    def __init__(self):
        self.class_b = ClassB()
        self.class_c = ClassC()
        self.count = 0
Copier après la connexion

Nous souhaitons définir une valeur pour chaque champ de cette classe lors des tests. Cette valeur peut être Aucune ou une classe simulée, mais nous ne voulons pas d'initiations des classes ClassB et ClassC.

Dans notre cas, décidons que self.class_b et self.class_c doivent être simulés :

@pytest.fixture
def mock_class_b():
    class_b = Mock(spec=ClassB)
    return class_b

@pytest.fixture
def mock_class_c():
    class_c = Mock(spec=ClassC)
    return class_c
Copier après la connexion

Donc, un montage pour cette classe qui sert notre objectif ressemble à ceci :

@pytest.fixture
def class_a_mock(mock_class_b, mock_class_c):
    with patch.object(target=ClassA, attribute="__init__", return_value=None) as mock_init:
        class_a = ClassA()
        class_a.class_b = mock_class_b
        class_a.class_c = mock_class_c
        class_b.count = 0
        return class_a

Copier après la connexion

La partie importante est de savoir comment utiliser la fonction patch.object, qui provient du module unittest.mock en Python. Il est utilisé dans les tests pour remplacer temporairement un attribut d'un objet donné par une valeur fictive ou une autre valeur.

Arguments

  1. target=ClassA : l'objet (généralement une classe) dont nous voulons patcher l'attribut.
  2. attribut="__init__" : le nom de l'attribut que nous voulons patcher.
  3. return_value=None : remplacement de la méthode __init__ par une fonction qui ne fait rien

De cette façon, nous pouvons créer des variables simulées dans notre luminaire.
En savoir plus sur patch.object

Conseils de test

J'ai écrit ce tutoriel pour ce genre de cas où, pour une raison quelconque, on ne peut pas changer le code de la Classe A. Cependant, je recommande généralement de modifier le code si possible, non pas pour changer la logique, mais pour le rendre plus testable .

Voici quelques exemples de modifications de la classe A pour la rendre plus testable :

Option 1 : Passer les instances de classe B et de classe C comme paramètres.
De cette façon, lorsque nous écrivons le luminaire, nous pouvons transmettre des simulations au lieu d'instances.

class ClassA:
    def __init__(self, class_b_instance, class_c_instance):
        self.class_b = class_b_instance
        self.class_c = class_c_instance
        self.count = 0
Copier après la connexion

Option 2 : Créez une variable booléenne qui indique le mode test.
De cette façon, nous pouvons décider quels champs de classe A obtiendront ou non une valeur lors de son initiation.

class ClassA:
    def __init__(self, test_mode=False):
        if not test_mode:
            self.class_b = ClassB()
            self.class_c = ClassC()
        self.count = 0
Copier après la connexion

Option 3 : Effectuer des initiations de cours selon une méthode distincte.
Cette approche nous donne le choix d'éviter d'appeler set_class_variables dans le module de test.

class ClassA:
    def __init__(self):
        self.class_b = None
        self.class_c = None
        self.count = None

    def set_class_variables(self):
        self.class_b = ClassB()
        self.class_c = ClassC()
        self.count = 0
Copier après la connexion

J'espère que cela vous aidera ! :)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal