Estoy usando pythons mock.patch y me gustaría cambiar el valor de retorno para cada llamada. Aquí está la advertencia: la función que se está parcheando no tiene entradas, por lo que no puedo cambiar el valor de retorno en función de la entrada.
Aquí está mi código de referencia.
def get_boolean_response():
response = io.prompt('y/n').lower()
while response not in ('y', 'n', 'yes', 'no'):
io.echo('Not a valid input. Try again'])
response = io.prompt('y/n').lower()
return response in ('y', 'yes')
Mi código de prueba:
@mock.patch('io')
def test_get_boolean_response(self, mock_io):
#setup
mock_io.prompt.return_value = ['x','y']
result = operations.get_boolean_response()
#test
self.assertTrue(result)
self.assertEqual(mock_io.prompt.call_count, 2)
io.prompt
es solo una versión independiente de plataforma (python 2 y 3) de "input". Así que, en última instancia, estoy tratando de burlarme de la entrada de los usuarios. He intentado usar una lista para el valor de retorno, pero eso no parece funcionar.
Puede ver que si el valor de retorno es algo no válido, obtendré un bucle infinito aquí. Entonces, necesito una forma de cambiar eventualmente el valor de retorno, para que mi prueba realmente finalice.
(Otra posible forma de responder a esta pregunta podría ser explicar cómo podría imitar la entrada del usuario en una prueba unitaria)
No es un duplicado de esta pregunta principalmente porque no tengo la capacidad de variar las entradas.
Uno de los comentarios de la respuesta a esta pregunta es similar, pero no se ha proporcionado respuesta / comentario.
fuente
response is not 'y' or 'n' or 'yes' or 'no'
en no hacer lo que crees que hace. Consulte ¿Cómo pruebo una variable con varios valores? y usted debe no utilizaris
para comparar los valores de cadena, el uso==
de comparar los valores , no identidades de objetos.is
para comparar literales de cadena. No hagas eso. El hecho de que funcione (a veces) es solo un detalle de implementación en CPython. Además,response is not 'y' or 'n' or 'yes' or 'no'
probablemente no está haciendo lo que crees que es ...Respuestas:
Puede asignar un iterable a
side_effect
, y el simulacro devolverá el siguiente valor en la secuencia cada vez que se llame:Citando la
Mock()
documentación :Como acotación al margen, la prueba
response is not 'y' or 'n' or 'yes' or 'no'
será no trabajar; se pregunta si la expresión(response is not 'y')
es verdadera o'y'
verdadera (siempre es el caso, una cadena no vacía siempre es verdadera), etc. Las diversas expresiones a cada lado de losor
operadores son independientes . Consulte ¿Cómo pruebo una variable con varios valores?Tampoco debe usar
is
para probar contra una cadena. El intérprete de CPython puede reutilizar objetos de cadena bajo ciertas circunstancias , pero este no es un comportamiento con el que debe contar.Como tal, use:
en lugar; esto usará pruebas de igualdad (
==
) para determinar si haceresponse
referencia a una cadena con el mismo contenido (valor).Lo mismo se aplica a
response == 'y' or 'yes'
; utilizarresponse in ('y', 'yes')
en su lugar.fuente
mock
? ¿Hay alguna manera de usar el parche con MagicMock como lo estoy haciendo con el simulacro estándar?Mock
clase stardard .m.side_effect = iter(['foo', 'bar', 'baz'])
).lambda
(una función), no unaMagicMock
. Un objeto de función no puede tener propiedades, por lo que elside_effect
atributo tiene que ser un iterable. Sin embargo, no deberías estar especificando el método así. Mejor usomock.patch.object(requests.Session, 'post')
; eso da como resultado un objeto de parche que se autoespecifica correctamente en el método y es compatible de maneraside_effect
adecuada.StopIteration
se eleva. Puede usar cualquier iterador, por lo que podría usaritertools.chain(['Foo'], itertools.repeat('Bar'))
para producirFoo
una vez y luego producir para siempreBar
.