Objeto de simulación de Python con método llamado varias veces
Tengo una clase que estoy probando que tiene como dependencia otra clase (una instancia de la cual se pasa al método init del CORTE). Quiero burlarme de esta clase usando la biblioteca de simulación de Python.
Lo que tengo es algo como:
mockobj = Mock(spec=MyDependencyClass)
mockobj.methodfromdepclass.return_value = "the value I want the mock to return"
assertTrue(mockobj.methodfromdepclass(42), "the value I want the mock to return")
cutobj = ClassUnderTest(mockobj)
Lo cual está bien, pero "methodfromdepclass" es un método parametrizado, y como tal quiero crear un único objeto mock donde dependiendo de qué argumentos se pasan a methodfromdepclass devuelve diferentes valores.
El la razón por la que quiero este comportamiento parametrizado es que quiero crear múltiples instancias de ClassUnderTest que contengan diferentes valores (cuyos valores son producidos por lo que se devuelve del mockobj).
Un poco lo que estoy pensando (esto, por supuesto, no funciona):
mockobj = Mock(spec=MyDependencyClass)
mockobj.methodfromdepclass.ifcalledwith(42).return_value = "you called me with arg 42"
mockobj.methodfromdepclass.ifcalledwith(99).return_value = "you called me with arg 99"
assertTrue(mockobj.methodfromdepclass(42), "you called me with arg 42")
assertTrue(mockobj.methodfromdepclass(99), "you called me with arg 99")
cutinst1 = ClassUnderTest(mockobj, 42)
cutinst2 = ClassUnderTest(mockobj, 99)
# now cutinst1 & cutinst2 contain different values
¿Cómo logro este tipo de semántica "ifcalledwith"?
3 answers
Intenta side_effect
def my_side_effect(*args, **kwargs):
if args[0] == 42:
return "Called with 42"
elif args[0] == 43:
return "Called with 43"
elif kwarg['foo'] == 7:
return "Foo is seven"
mockobj.mockmethod.side_effect = my_side_effect
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-05 18:29:20
Un poco más dulce:
mockobj.method.side_effect = lambda x: {123: 100, 234: 10000}[x]
O para múltiples argumentos:
mockobj.method.side_effect = lambda *x: {(123, 234): 100, (234, 345): 10000}[x]
O con un valor predeterminado:
mockobj.method.side_effect = lambda x: {123: 100, 234: 10000}.get(x, 20000)
O una combinación de ambos:
mockobj.method.side_effect = lambda *x: {(123, 234): 100, (234, 345): 10000}.get(x, 20000)
Y alegremente en lo alto vamos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-29 23:04:56
Me he encontrado con esto cuando estaba haciendo mis propias pruebas. Si no te importa capturar llamadas a tu methodfromdepclass() pero solo lo necesitas para devolver algo, entonces lo siguiente puede ser suficiente:
def makeFakeMethod(mapping={}):
def fakeMethod(inputParam):
return mapping[inputParam] if inputParam in mapping else MagicMock()
return fakeMethod
mapping = {42:"Called with 42", 59:"Called with 59"}
mockobj.methodfromdepclass = makeFakeMethod(mapping)
Aquí hay una versión parametrizada:
def makeFakeMethod():
def fakeMethod(param):
return "Called with " + str(param)
return fakeMethod
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-11 22:14:58