Pregunta Python se burla de múltiples valores de retorno


Estoy usando pitons mock.patch y me gustaría cambiar el valor de retorno para cada llamada. Aquí está la advertencia: la función que se está reparando 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 la plataforma (python 2 y 3) de "entrada". Entonces, en última instancia, estoy tratando de burlar la entrada de los usuarios. He intentado usar una lista para el valor de retorno, pero eso no funciona.

Puedes ver que si el valor de retorno es inválido, obtendré un bucle infinito aquí. Entonces necesito una forma de cambiar eventualmente el valor de retorno, para que mi prueba realmente termine.

(Otra posible forma de responder esta pregunta podría ser explicar cómo podría imitar la entrada del usuario en una prueba unitaria)


No es un dup esta pregunta principalmente porque no tengo la capacidad de variar las entradas.

Uno de los comentarios de la Respuesta sobre esta pregunta está en la misma línea, pero no se ha proporcionado ninguna respuesta / comentario.


75
2017-07-22 20:25


origen


Respuestas:


Puedes asignar un iterable a side_effect, y el simulacro devolverá el siguiente valor en la secuencia cada vez que se llame:

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'

Citando el Mock() documentación:

Si side_effect es un iterable entonces cada llamada al simulacro devolverá el siguiente valor de iterable.

Como un lado, la prueba response is not 'y' or 'n' or 'yes' or 'no' será no trabajo; usted está preguntando si la expresión (response is not 'y') es cierto, o 'y' es verdadero (siempre es el caso, una cadena no vacía siempre es verdadera), etc. Las diversas expresiones en cada lado de or los operadores son independiente. Ver ¿Cómo pruebo una variable contra múltiples valores?

Debieras además No utilice is para probar contra una cadena. El intérprete CPython mayo reutilizar objetos de cadena bajo ciertas circunstancias, pero este no es un comportamiento con el que deberías contar.

Como tal, usa:

response not in ('y', 'n', 'yes', 'no')

en lugar; esto usará igualdad pruebas (==) para determinar si response hace referencia a una cadena con los mismos contenidos (valor).

Lo mismo aplica a response == 'y' or 'yes'; utilizar response in ('y', 'yes') en lugar.


147
2017-07-22 20:34