web-dev-qa-db-de.com

Wie liefert man eine Mock-Klassenmethode für den Python-Unit-Test?

Nehmen wir an, ich habe eine Klasse wie diese.

   class SomeProductionProcess(CustomCachedSingleTon):

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

           pass

Zum Testzeitpunkt möchte ich die Logik in der loaddata()-Methode ändern. Es wäre eine einfache benutzerdefinierte Logik, die keine großen Daten verarbeitet.

Wie liefern wir eine benutzerdefinierte Implementierung von loaddata() zur Testzeit mit Python Mock UnitTest-Framework?

8
Vineel

Hier ist eine einfache Möglichkeit, mit Mock zu arbeiten

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

Ich würde empfehlen, pytest anstelle des unittest-Moduls zu verwenden, wenn Sie können. Der Testcode wird dadurch viel sauberer und die Anzahl der Boilerplates, die Sie mit unittest.TestCase- Tests erhalten, wird reduziert.

12
Brendan Abel

Um eine Klassenmethode mit einem strukturierten return_value mockout zu machen, können Sie unittest.mock.Mock verwenden.

from unittest.mock import Mock

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

BEARBEITEN:

Da Sie die Methode mit einer benutzerdefinierten Implementierung simulieren möchten, können Sie einfach ein benutzerdefiniertes Mock-Methodenobjekt erstellen und die ursprüngliche Methode zur Laufzeit testen.

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

SomeProductionProcess.loaddata = custom_method
5
Mattew Whitt

Nehmen wir an, Sie haben ein Modul namens awesome.py und darin hatten Sie:

import time

class SomeProductionProcess(CustomCachedSingleTon):

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

Dann könnte Ihr einziger Ort, an dem Sie loaddata verspotten, folgendermaßen aussehen:

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)

Oder es könnte so aussehen:

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)

Wenn Sie jetzt Ihren Test ausführen, dauert loaddata für diese Testfälle keine 30 Sekunden.

2
willnx