Estoy escribiendo pruebas para una función como la siguiente:
def foo():
print 'hello world!'
Entonces, cuando quiera probar esta función, el código será así:
import sys
from foomodule import foo
def test_foo():
foo()
output = sys.stdout.getline().strip() # because stdout is an StringIO instance
assert output == 'hello world!'
Pero si ejecuto nosetests con el parámetro -s, la prueba falla. ¿Cómo puedo captar la salida con unittest o módulo de nariz?
python
unit-testing
nosetests
python-nose
Pedro Valencia
fuente
fuente

with mock.patch('sys.stdout', new_callable=StringIO.StringIO):pypi.python.org/pypi/mockRespuestas:
Utilizo este administrador de contexto para capturar la salida. En última instancia, utiliza la misma técnica que algunas de las otras respuestas reemplazando temporalmente
sys.stdout. Prefiero el administrador de contexto porque envuelve toda la contabilidad en una sola función, por lo que no tengo que volver a escribir ningún código de prueba final, y no tengo que escribir funciones de configuración y desmontaje solo para esto.Úselo así:
Además, dado que el estado de salida original se restaura al salir del
withbloque, podemos configurar un segundo bloque de captura en la misma función que el primero, lo cual no es posible usando las funciones de configuración y desmontaje, y se vuelve prolijo al escribir try-finalmente bloques manualmente. Esa capacidad resultó útil cuando el objetivo de una prueba era comparar los resultados de dos funciones entre sí en lugar de con algún valor precalculado.fuente
TypeError: unicode argument expected, got 'str'(el tipo pasado para imprimir (str / unicode) es irrelevante).from io import BytesIO as StringIOy en Python 3 solofrom io import StringIO. Creo que pareció solucionar el problema en mis pruebas.strip()alunicodedevueltoStringIO.getvalue()?sys. Con su declaración de importación, está creando una variable local llamadastderrque recibió una copia del valor en formatosys.stderr. Los cambios en uno no se reflejan en el otro.Si realmente desea hacer esto, puede reasignar sys.stdout durante la prueba.
Sin embargo, si estuviera escribiendo este código, preferiría pasar un
outparámetro opcional a lafoofunción.Entonces la prueba es mucho más simple:
fuente
StringIOclase ahora debe importarse desde eliomódulo.from io import StringIOfunciona en python 2.6+.from io import StringIOen python 2, obtiene unTypeError: unicode argument expected, got 'str'al imprimir.with redirect_stdout(out):saved_stdout = sys.stdout, siempre tiene una referencia mágica para esto ensys.__stdout__, por ejemplo, solo lo necesitasys.stdout = sys.__stdout__en su limpieza.Desde la versión 2.7, ya no necesita reasignar
sys.stdout, esto se proporciona a través debufferflag . Además, es el comportamiento predeterminado de nosetest.Aquí hay un ejemplo de falla en un contexto sin búfer:
Puede configurar búfer a través de
unit2la línea de órdenes-b,--buffero enunittest.mainopciones. Lo contrario se consigue mediantenosetestbandera--nocapture.fuente
--nocapture; en particular, si se establece esta bandera, el modo en búfer se desactivará. Por lo tanto, tiene la opción de poder ver la salida en el terminal o de poder probar que la salida es la esperada.Muchas de estas respuestas me fallaron porque no puedes
from StringIO import StringIOen Python 3. Aquí hay un fragmento de trabajo mínimo basado en el comentario de @ naxa y el Libro de recetas de Python.fuente
En python 3.5 puede usar
contextlib.redirect_stdout()yStringIO(). Aquí está la modificación de su códigofuente
redirect_stdout()yredirect_stderr()devuelve su argumento de entrada. Entonces,with contextlib.redirect_stdout(StringIO()) as temp_stdout:te da todo en una línea. Probado con 3.7.1.Recién estoy aprendiendo Python y me encontré luchando con un problema similar al anterior con pruebas unitarias para métodos con salida. Mi prueba unitaria aprobada para el módulo foo anterior terminó luciendo así:
fuente
sys.stdout.getvalue().strip()y no hacer trampa en comparación con\n:)from io import StringIOEscribir pruebas a menudo nos muestra una mejor manera de escribir nuestro código. Similar a la respuesta de Shane, me gustaría sugerir otra forma de ver esto. ¿Realmente quiere afirmar que su programa generó una determinada cadena, o simplemente que construyó una determinada cadena para la salida? Esto se vuelve más fácil de probar, ya que probablemente podamos asumir que la
printdeclaración de Python hace su trabajo correctamente.Entonces tu prueba es muy simple:
Por supuesto, si realmente necesita probar la salida real de su programa, no dude en ignorarlo. :)
fuente
foo()no hace nada más que llamar a la declaración de impresión, probablemente no sea un problema.Basado en la respuesta de Rob Kennedy, escribí una versión basada en clases del administrador de contexto para almacenar la salida.
El uso es como:
Aquí está la implementación:
fuente
O considere usarlo
pytest, tiene soporte incorporado para afirmar stdout y stderr. Ver documentosfuente
Tanto n611x007 y Noúmeno ya se ha sugerido el uso
unittest.mock, pero esta respuesta se adapta Acumenus de mostrar cómo se puede envolver fácilmenteunittest.TestCasemétodos para interactuar con un objeto de burlastdout.fuente
Sobre la base de todas las respuestas increíbles en este hilo, así es como lo resolví. Quería mantenerlo lo más stock posible. Aumenté el mecanismo de prueba unitaria usando
setUp()para capturarsys.stdoutysys.stderr, agregué nuevas API de aserción para verificar los valores capturados con un valor esperado y luego restaurarsys.stdoutysys.stderrentearDown(). I did this to keep a similar unit test API as the built-inunittestAPI while still being able to unit test values printed tosys.stdoutorsys.stderr`.Cuando se ejecuta la prueba unitaria, la salida es:
fuente