2 votes

Unittest. appelé ne fonctionne pas lorsque la méthode est appelée via une variable qui la référence

J'ai quelque chose comme ça dans mon code :

def submethod_a():
    pass

def submethod_b():
    pass

_method_registry = {
    "a": submethod_a,
    "b": submethod_b,
}

def main_method(key):
    method_to_use = _method_registry[key]
    method_to_use()

Et ensuite j'ai quelque chose comme ça dans mon test :

from unittest.mock import patch

@patch("submethod_b")
def test_correct_method_and_arguments(mocked_submethod_b):
    main_method(key)

    assert mocked_submethod_b.called

Et le test échoue. J'ai fait ceci pour tester :

def main_method(key):
    if key == "a":
        submethod_a()
    else:
        submethod_b()

Et ensuite le test fonctionne.

Donc, .called ne fonctionne pas lorsque la méthode est dans une référence ? Est-ce le comportement attendu ? Que puis-je faire ? Si je ne trouve pas d'autre solution, je pense que je vais refactoriser le code et utiliser des classes avec 2 implémentations différentes de "submethod", je pense que cela devrait fonctionner.

Merci.

1voto

Lorsque le code source a été initialement lu, la fonction submethod_b d'origine était déjà stockée dans la variable _method_registry, donc au moment où vous l'avez corrigée à l'exécution, bien que la fonction ait été remplacée, elle n'a pas modifié la valeur déjà stockée dans cette variable. Pour le prouver, ajoutons des impressions.

main.py

def submethod_a():
    pass

def submethod_b():
    pass

_method_registry = {
    "a": submethod_a,
    "b": submethod_b,
}

def main_method(key):
    print(_method_registry["b"], "- Fonction stockée")
    print(submethod_b, "- Fonction corrigée")

test_main.py

from unittest.mock import patch

from main import main_method

def test_no_patch():
    main_method("b")

@patch("main.submethod_b")
def test_with_patch(mocked_submethod_b):
    main_method("b")

Sortie

$ pytest -q -rP
================================================================================================= RÉUSSITES ==================================================================================================
______________________________________________________________________________________________ test_no_patch ______________________________________________________________________________________________
------------------------------------------------------------------------------------------ Sortie stdout -------------------------------------------------------------------------------------------
 - Fonction stockée
 - Fonction corrigée
_____________________________________________________________________________________________ test_with_patch _____________________________________________________________________________________________
------------------------------------------------------------------------------------------ Sortie stdout -------------------------------------------------------------------------------------------
 - Fonction stockée
 - Fonction corrigée
2 passed in 0.04s

Comme vous pouvez le voir, sans le patch, la valeur est simplement la même fonction d'origine. Mais avec le patch, remarquez que seule la fonction effective a été remplacée, pas celle déjà stockée.

Solution Alternative

  1. Placez les fonctions submethod dans leur propre fichier.
  2. Importez les subméthodes dans votre fichier principal et utilisez-les comme initialement fait.
  3. Corrigez le fichier subméthode.
  4. Rechargez le fichier principal pour que les subméthodes corrigées soient utilisées lors de la recréation du _method_registry.

main.py

from submethod import submethod_a, submethod_b  # Ou : import submethod

_method_registry = {
    "a": submethod_a,  # En fonction du style d'importation choisi, cela peut être : submethod.submethod_a
    "b": submethod_b,  # En fonction du style d'importation choisi, cela peut être : submethod.submethod_b
}

def main_method(key):
    print(_method_registry["b"], "- Fonction stockée")
    print(submethod_b, "- Fonction corrigée")

    methode_a_utiliser = _method_registry[key]
    methode_a_utiliser()

submethod.py

def submethod_a():
    pass

def submethod_b():
    pass

test_main.py

from importlib import reload
import sys

from unittest.mock import patch

from main import main_method

@patch("submethod.submethod_b")
def test_with_patch(mocked_submethod_b):
    # Maintenant que le patch est en effet et a remplacé le submethod.submethod_b, recharger le fichier principal pour recréer _method_registry avec la fonction corrigée
    reload(sys.modules['main'])

    main_method("b")

    assert mocked_submethod_b.called

Sortie

$ pytest -q -rP
================================================================================================= RÉUSSITES ==================================================================================================
_____________________________________________________________________________________________ test_with_patch _____________________________________________________________________________________________
------------------------------------------------------------------------------------------ Sortie stdout -------------------------------------------------------------------------------------------
 - Fonction stockée
 - Fonction corrigée
1 passed in 0.04s

Maintenant, la fonction stockée et la fonction corrigée elles-mêmes pointent toutes les deux vers la version simulée. Ainsi, l'assertion .called est maintenant réussie.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X