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?
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.
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
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.