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
with
bloque, 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 StringIO
y en Python 3 solofrom io import StringIO
. Creo que pareció solucionar el problema en mis pruebas.strip()
alunicode
devueltoStringIO.getvalue()
?sys
. Con su declaración de importación, está creando una variable local llamadastderr
que 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
out
parámetro opcional a lafoo
función.Entonces la prueba es mucho más simple:
fuente
StringIO
clase ahora debe importarse desde elio
módulo.from io import StringIO
funciona en python 2.6+.from io import StringIO
en 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 debuffer
flag . 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
unit2
la línea de órdenes-b
,--buffer
o enunittest.main
opciones. Lo contrario se consigue mediantenosetest
bandera--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 StringIO
en 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 StringIO
Escribir 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
print
declaració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.TestCase
mé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.stdout
ysys.stderr
, agregué nuevas API de aserción para verificar los valores capturados con un valor esperado y luego restaurarsys.stdout
ysys.stderr
entearDown(). I did this to keep a similar unit test API as the built-in
unittestAPI while still being able to unit test values printed to
sys.stdoutor
sys.stderr`.Cuando se ejecuta la prueba unitaria, la salida es:
fuente