web-dev-qa-db-fra.com

Comment fournir une méthode de classe fictive pour le test d'unité python?

Disons que j'ai un cours comme celui-ci.

   class SomeProductionProcess(CustomCachedSingleTon):

       def loaddata():
           """
           Uses an iterator over a large file in Production for the Data pipeline.
           """

           pass

Maintenant, au moment du test, je souhaite modifier la logique de la méthode loaddata(). Ce serait une simple logique personnalisée qui ne traite pas de grandes données.

Comment pouvons-nous fournir une implémentation personnalisée de loaddata() lors du test à l'aide de la structure Python Mock UnitTest?

8
Vineel

Voici un moyen simple de le faire en utilisant mock

import mock


def new_loaddata(cls, *args, **kwargs):
    # Your custom testing override
    return 1


def test_SomeProductionProcess():
    with mock.patch.object(SomeProductionProcess, 'loaddata', new=new_loaddata):
        obj = SomeProductionProcess()
        obj.loaddata()  # This will call your mock method

Je vous recommande d'utiliser pytest au lieu du module unittest si vous en êtes capable. Cela rend votre code de test beaucoup plus propre et réduit considérablement le nombre de tests obtenus avec les tests de style unittest.TestCase-.

12
Brendan Abel

Pour simuler facilement une méthode de classe avec une valeur retournée structurée, vous pouvez utiliser unittest.mock.Mock.

from unittest.mock import Mock

mockObject = SomeProductionProcess
mockObject.loaddata = Mock(return_value=True)

MODIFIER:

Puisque vous voulez simuler la méthode avec une implémentation personnalisée, vous pouvez simplement créer un objet de méthode simulé et échanger la méthode d'origine lors du test de l'exécution.

def custom_method(*args, **kwargs):
    # do custom implementation

SomeProductionProcess.loaddata = custom_method
5
Mattew Whitt

Disons que vous avez un module nommé awesome.py et que vous y aviez:

import time

class SomeProductionProcess(CustomCachedSingleTon):

    def loaddata(self):
        time.sleep(30) # simulating a long running process
        return 2

Dans ce cas, votre plus-part où vous vous moquez de loaddata pourrait ressembler à ceci:

import unittest

import awesome # your application module


class TestSomeProductionProcess(unittest.TestCase):
    """Example of direct monkey patching"""

    def test_loaddata(self):
        some_prod_proc = awesome.SomeProductionProcess()
        some_prod_proc.loaddata = lambda x: 2 # will return 2 every time called
        output = some_prod_proc.loaddata()
        expected = 2

        self.assertEqual(output, expected)

Ou cela pourrait ressembler à ceci:

import unittest
from mock import patch

import awesome # your application module

class TestSomeProductionProcess(unittest.TestCase):
    """Example of using the mock.patch function"""

    @patch.object(awesome.SomeProductionProcess, 'loaddata')
    def test_loaddata(self, fake_loaddata):
        fake_loaddata.return_value = 2
        some_prod_proc = awesome.SomeProductionProcess()

        output = some_prod_proc.loaddata()
        expected = 2

        self.assertEqual(output, expected)

Désormais, lorsque vous exécuterez votre test, loaddata ne prendra pas 30 secondes pour ces cas de test.

2
willnx