J'ai essayé d'implémenter des tests unitaires pour un module. Un exemple de module nommé alphabet.py est le suivant:
import database
def length_letters():
return len(letters)
def contains_letter(letter):
return True if letter in letters else False
letters = database.get('letters') # returns a list of letters
Je voudrais me moquer de la réponse d'une base de données avec certaines valeurs de mon choix, mais le code ci-dessous ne semble pas fonctionner.
import unittests
import alphabet
from unittest.mock import patch
class TestAlphabet(unittest.TestCase):
@patch('alphabet.letters')
def setUp(self, mock_letters):
mock_letters.return_value = ['a', 'b', 'c']
def test_length_letters(self):
self.assertEqual(3, alphabet.length_letters())
def test_contains_letter(self):
self.assertTrue(alphabet.contains_letter('a'))
J'ai vu de nombreux exemples dans lesquels "patch" est appliqué aux méthodes et aux classes, mais pas aux variables. Je préfère ne pas appliquer de correctif à la méthode database.get car je pourrais l’utiliser ultérieurement avec des paramètres différents, j’aurais donc besoin d’une réponse différente.
Qu'est-ce que je fais mal ici?
Vous n'avez pas besoin de vous moquer. Importez simplement le module et modifiez la valeur du global dans setUp()
:
import alphabet
class TestAlphabet(unittest.TestCase):
def setUp(self):
alphabet.letters = ['a', 'b', 'c']
Essaye ça:
import unittests
import alphabet
from unittest.mock import patch
class TestAlphabet(unittest.TestCase):
def setUp(self):
self.mock_letters = mock.patch.object(
alphabet, 'letters', return_value=['a', 'b', 'c']
)
def test_length_letters(self):
with self.mock_letters:
self.assertEqual(3, alphabet.length_letters())
def test_contains_letter(self):
with self.mock_letters:
self.assertTrue(alphabet.contains_letter('a'))
Vous devez appliquer le modèle pendant que les tests individuels sont en cours d'exécution, pas seulement dans setUp()
. Nous pouvons créer la maquette dans setUp()
et l’appliquer ultérieurement avec un with ...
Gestionnaire de contexte.
Les variables peuvent être corrigées par (Python2)
from mock import patch
@patch('module.variable', new_value)
Par exemple:
import alphabet
from mock import patch
@patch('alphabet.letters', ['a', 'b', 'c'])
class TestAlphabet():
def test_length_letters(self):
assert 3 == alphabet.length_letters()
def test_contains_letter(self):
assert alphabet.contains_letter('a')
Cela devrait également fonctionner pour Python3, je suppose, puisque mock est un backport de unittest.mock
J'ai rencontré un problème en essayant de simuler des variables utilisées en dehors de toute fonction ou classe, ce qui est problématique car elles sont utilisées dès que vous essayez de vous moquer de la classe, avant de pouvoir vous moquer des valeurs.
J'ai fini par utiliser une variable d'environnement. Si la variable d'environnement existe, utilisez cette valeur, sinon utilisez la valeur par défaut de l'application. De cette façon, je pourrais définir la valeur de la variable d'environnement dans mes tests.
Dans mon test, j'avais ce code avant l'importation de la classe
os.environ["PROFILER_LOG_PATH"] = "./"
Dans ma classe:
log_path = os.environ.get("PROFILER_LOG_PATH",config.LOG_PATH)
Par défaut, mon config.LOG_PATH
est /var/log/<my app name>
, mais maintenant, lorsque le test est en cours d'exécution, le chemin du journal est défini sur le répertoire actuel. De cette façon, vous n'avez pas besoin d'un accès root pour exécuter les tests.