python - skipif - ¿Cómo puedo simular la entrada a stdin para pyunit?
unittest python 3 (5)
Actualización - utilizando unittest.mock.patch
Desde Python 3.3, hay un nuevo submódulo para unittest
llamado mock que hace exactamente lo que necesita hacer. Para aquellos que usan Python 2.6 o superior hay un backport de mock
encuentra here .
import unittest
from unittest.mock import patch
import module_under_test
class MyTestCase(unittest.TestCase):
def setUp(self):
# raw_input is untouched before test
assert module_under_test.raw_input is __builtins__.raw_input
def test_using_with(self):
input_data = "123"
expected = int(input_data)
with patch.object(module_under_test, "raw_input", create=True,
return_value=expected):
# create=True is needed as raw_input is not in the globals of
# module_under_test, but actually found in __builtins__ .
actual = module_under_test.function()
self.assertEqual(expected, actual)
@patch.object(module_under_test, "raw_input", create=True)
def test_using_decorator(self, raw_input):
raw_input.return_value = input_data = "123"
expected = int(input_data)
actual = module_under_test.function()
self.assertEqual(expected, actual)
def tearDown(self):
# raw input is restored after test
assert module_under_test.raw_input is __builtins__.raw_input
if __name__ == "__main__":
unittest.main()
# where module_under_test.function is:
def function():
return int(raw_input("prompt> "))
Respuesta anterior - reemplazando sys.stdin
Creo que el módulo sys podría ser lo que estás buscando.
Puedes hacer algo como
import sys
# save actual stdin in case we need it again later
stdin = sys.stdin
sys.stdin = open(''simulatedInput.txt'',''r'')
# or whatever else you want to provide the input eg. StringIO
raw_input ahora leerá desde simulatedInput.txt cada vez que se llame. Si los contenidos de simulatedInput fueran
hello
bob
luego la primera llamada a raw_input devolvería "hola", la segunda "bob" y la tercera lanzaría un EOFError ya que no había más texto para leer.
Estoy tratando de probar una función que toma entrada de stdin
, que actualmente estoy probando con algo como esto:
cat /usr/share/dict/words | ./spellchecker.py
En el nombre de la automatización de prueba, ¿hay alguna manera en que pyunit
pueda falsificar la entrada a raw_input()
?
La respuesta corta es mono patch raw_input()
.
Hay algunos buenos ejemplos en la respuesta a ¿Cómo mostrar la entrada estándar redirigida en Python?
Este es un ejemplo simple y trivial que utiliza un lambda
que desecha la solicitud y devuelve lo que queremos.
Sistema bajo prueba
cat ./name_getter.py
#!/usr/bin/env python
class NameGetter(object):
def get_name(self):
self.name = raw_input(''What is your name? '')
def greet(self):
print ''Hello, '', self.name, ''!''
def run(self):
self.get_name()
self.greet()
if __name__ == ''__main__'':
ng = NameGetter()
ng.run()
$ echo Derek | ./name_getter.py
What is your name? Hello, Derek !
Caso de prueba:
$ cat ./t_name_getter.py
#!/usr/bin/env python
import unittest
import name_getter
class TestNameGetter(unittest.TestCase):
def test_get_alice(self):
name_getter.raw_input = lambda _: ''Alice''
ng = name_getter.NameGetter()
ng.get_name()
self.assertEquals(ng.name, ''Alice'')
def test_get_bob(self):
name_getter.raw_input = lambda _: ''Bob''
ng = name_getter.NameGetter()
ng.get_name()
self.assertEquals(ng.name, ''Bob'')
if __name__ == ''__main__'':
unittest.main()
$ ./t_name_getter.py -v
test_get_alice (__main__.TestNameGetter) ... ok
test_get_bob (__main__.TestNameGetter) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
No describiste qué tipo de código está en spellchecker.py
, lo que me da libertad para especular.
Supongamos que es algo como esto:
import sys
def check_stdin():
# some code that uses sys.stdin
Para mejorar la check_stdin
de check_stdin
función check_stdin
, propongo refactorizarla así:
def check_stdin():
return check(sys.stdin)
def check(input_stream):
# same as original code, but instead of
# sys.stdin it is written it terms of input_stream.
Ahora, la mayor parte de su lógica está en la función de check
, y puede elaborar manualmente cualquier entrada que pueda imaginar para probarla correctamente, sin necesidad de lidiar con la stdin
.
Mis 2 centavos.
Reemplace sys.stdin
con una instancia de StringIO
y cargue la instancia de StringIO
con los datos que desea que se devuelvan a través de sys.stdin
. Además, sys.__stdin__
contiene el objeto sys.stdin
original, por lo que restaurar sys.stdin
después de su prueba es tan simple como sys.stdin = sys.__stdin__
.
Fudge es un excelente módulo simulado de python, con decoradores convenientes para hacer parches de este tipo, con limpieza automática. Usted deberia comprobar esto.
Si está utilizando un módulo simulado (escrito por Michael Foord), para simular la función raw_input puede usar una sintaxis como:
@patch(''src.main.raw_input'', create=True, new=MagicMock(return_value=''y''))
def test_1(self):
method_we_try_to_test(); # method or function that calls **raw_input**