test - En Python, ¿cómo hacer la prueba unitaria en una función sin valor de retorno?
unittest python español (6)
Como se mencionó en otra respuesta, puede usar la biblioteca simulada de Python para hacer afirmaciones sobre las llamadas a funciones / métodos
from mock import patch
from my_module import HelloTest
import unittest
class TestFoo(unittest.TestCase):
@patch(''hello.HelloTest.bar'')
def test_foo_case(self, mock_bar):
ht = HelloTest()
ht.foo("some string")
self.assertEqual(ob.msg, "SOME STRING")
self.assertTrue(mock_bar.called)
Esto soluciona el método de la bar
en HelloTest y lo reemplaza con un objeto simulado que registra las llamadas en su contra.
La burla es un poco de un agujero de conejo. Solo hazlo cuando tengas que hacerlo porque hace que tus pruebas sean frágiles. Nunca notará un cambio de API para un objeto simulado, por ejemplo.
Soy un pitón. En estos días me estoy conduciendo para hacer una prueba de unidad más completa en algún módulo central de mi proyecto. Como siempre hacemos una prueba unitaria con los métodos ''assertEqual'', ''assertTrue'', etc., todos estos métodos requieren un valor de retorno de la función que se está probando, me pregunto cómo realizar una prueba unitaria simple en alguna función sin un valor de retorno.
Me gustaría mostrar un pequeño ejemplo aquí, ¿cómo probar la función def foo (self, msg) en HelloTest?
class HelloTest(object):
def foo(self, msg):
MSG = msg.upper()
self.bar(MSG)
def bar(self, MSG):
print MSG
En Python 3, puede indicar a la print
dónde imprimir :
imprimir (* objetos, sep = '''', final = ''/ n'', archivo = sys.stdout, flush = Falso)
Así que agregue un argumento opcional:
def bar(self, MSG, file=sys.stdout):
print(MSG, file=file)
En el uso normal, se imprimirá en la salida estándar, pero para las pruebas unitarias puede pasar su propio archivo.
En Python 2 es un poco más desordenado, pero puedes redireccionar stdout a un búfer StringIO :
import StringIO
import sys
out = StringIO.StringIO()
sys.stdout = out
# run unit tests
sys.stdout = sys.__stdout__
# check the contents of `out`
En este caso particular, me burlaría de la impresión y luego utilizaría el simulacro en mi afirmación.
En Python, usarás el paquete Mock para simularte.
Gracias a la introducción de @Jordan, codifico esto y creo que es una prueba de unidad viable para HelloTest.foo
from mock import Mock
import unittest
class HelloTestTestCase(unittest.TestCase):
def setUp(self):
self.hello_test = HelloTest()
def tearDown(self):
pass
def test_foo(self):
msg = ''hello''
expected_bar_arg = ''HELLO''
self.hello_test.bar = Mock()
self.hello_test.foo(msg)
self.hello_test.bar.assert_called_once_with(expected_bar_arg)
if __name__ == ''__main__'':
unittest.main()
No entiendo muy bien por qué todo el mundo quiere comprobar que la barra de llamadas de Foo.
Foo tiene alguna funcionalidad y esta funcionalidad necesita ser probada. Si foo está usando la barra para hacer esto, no debería ser mi preocupación.
El resultado deseado es que después de llamar a foo(msg)
, es que msg.upper()
se envía a stdout.
Puede redireccionar la salida estándar a un búfer de cadena y verificar si el contenido de este búfer de cadena coincide con lo que usted espera.
Ejemplo:
import sys
import unittest
from io import TextIOWrapper, BytesIO
class TestScript(unittest.TestCase):
def setUp(self):
self._old_stdout = sys.stdout
sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding)
def _output(self):
self._stdout.seek(0)
return self._stdout.read()
def test_foo(self):
hello_test = HelloTest()
hello_test.foo("blub")
self.assertEqual(self._output(), "BLUB")
def tearDown(self):
sys.stdout = self._old_stdout
self._stdout.close()
También puede hacer eso para stdin (y escribir en stdin para simular alguna entrada) y puede subclase TestIOWrapper si necesita hacer algo especial, como permitir que el texto no Unicode se envíe a sys.stdout
sin usar sys.stdout.buffer
(Python 2 vs. Python 3). Hay un ejemplo para eso en esta respuesta SO . Cuando (aún) usa Python 2 solamente, entonces usar StringIO
podría ser mejor que usar el módulo io.
Su código puede ser el que figura a continuación, que realiza la misma tarea que la anterior:
class HelloTest(object):
def foo(self, msg):
self.msg = msg.upper()
self.bar()
def bar(self):
print self.msg
La prueba unitaria es:
from hello import HelloTest
import unittest
class TestFoo(unittest.TestCase):
def test_foo_case(self):
msg = "test"
ob = HelloTest()
ob.foo(msg)
expected = "TEST"
self.assertEqual(ob.msg, expected)
if __name__ == ''__main__'':
unittest.main(exit=False)