2010-02-28 7 views
12

¿Cuál es la última forma de escribir pruebas de Python? ¿Qué módulos/marcos usar?¿Cómo escribir pruebas modernas de Python?

Y otra pregunta: ¿todavía hay pruebas de doctest de algún valor? ¿O deberían escribirse todas las pruebas en un marco de prueba más moderno?

Gracias, Boda Cydo.

Respuesta

12

La forma habitual es utilizar el módulo integrado unittest para crear pruebas unitarias y agruparlas en suites de prueba que se pueden ejecutar de forma independiente. unittest es muy similar a (e inspirado en) jUnit y por lo tanto muy fácil de usar.

Si usted está interesado en los cambios más recientes, echar un vistazo a la nueva charla PyCon por Michael Foord:

PyCon 2010: New and Improved: Coming changes to unittest

+0

¡Gracias por la respuesta! – bodacydo

5

no sé mucho acerca de prueba unitaria, pero en mi universidad, la prueba de la nariz se enseña y se anima.

nariz se puede instalar siguiendo este procedimiento (estoy asumiendo que usted está usando un PC - Windows OS):

  1. instalación setuptools
  2. cuadro de diálogo Ejecutar comandos de DOS (Inicio -> Todos los programas - > Accesorios -> Símbolo del sistema)
  3. Para que este paso funcione, debe estar conectado a internet. En DOS, escriba: C: \ Python25 \ Scripts \ easy_install nariz

Si usted está en un sistema operativo diferente, comprobar this site

EDITAR:

ya han pasado dos años desde que escribí originalmente esta publicación. Ahora, he aprendido de este principio de programación llamado Designing by Contract. Esto permite que un programador defina las condiciones previas, las postcondiciones y las invariantes (llamadas contratos) para todas las funciones en su código. El efecto es que se genera un error si se viola alguno de estos contratos.

marco el DBC que yo recomendaría para el pitón se llama PyContract he utilizado con éxito en mi evolutionary programming framework

+0

Voy a echar un vistazo a esto. ¡Gracias! – bodacydo

+1

Características interesantes de la nariz: no es necesario que subasifique TestCase, las convenciones de nomenclatura flexibles para las clases de TestCase, la capacidad de ejecutar doctests también. –

9

El uso de la incorporada en el módulo de unittest es tan relevante y fácil que nunca. Las otras opciones de prueba de unidad, py.test, nose y twisted.trial son en su mayoría compatibles con unittest.

Los archivos de prueba tienen el mismo valor que siempre: son excelentes para al probar su documentación, no su código. Si va a poner ejemplos de código en sus documentos, doctest puede asegurar que los mantenga correctos y actualizados. No hay nada peor que tratar de reproducir un ejemplo y fallar, solo para luego darse cuenta de que en realidad fue culpa de la documentación.

+2

Gracias por explicar doctests. No sabía su verdadero propósito, ahora lo hago. Intentaré usar unittest para probarlo. :) – bodacydo

+0

+1 para unittest, y me parece útil para ayudar a probar código más complejo (http://code.google.com/p/pymox) –

2

En mi proyecto actual estoy usando unittest, minimock, nose. En el pasado he usado mucho doctests, pero en proyectos grandes algunas pruebas pueden ser un poco difíciles de manejar, por lo que tiendo a reservar el uso de doctests para funciones más simples.

Si está utilizando setuptools o distribute (que debería estar cambiando a distribuir), puede configurar la nariz como el colector de prueba predeterminado para que pueda ejecutar las pruebas con "prueba setup.py pitón"

setup(name='foo', 
     ... 
     test_suite='nose.collector', 
     ... 

Ahora ejecutar "python setup.py test" invocará a nose, que rastreará su proyecto para buscar cosas que parezcan pruebas y las ejecute, acumulando los resultados. Si también tiene doctests en su proyecto, puede ejecutar nosetest con la opción --with-doctest para habilitar el complemento doctest.

nariz también tiene integración con coverage

nosetests --with-coverage. 

También puede utilizar los --cover-html --cover-html-dir opciones para generar un informe de cobertura de HTML para cada módulo, con cada línea del código que no está bajo prueba resaltado. No me obsesionaría demasiado con obtener cobertura para informar el 100% de cobertura de prueba para todos los módulos. Es mejor dejar algún código para las pruebas de integración, que cubriré al final.

Me he convertido en un gran admirador de minimock, ya que hace que el código de prueba con muchas dependencias externas sea realmente fácil. Si bien funciona realmente bien cuando se combina con doctest, se puede usar con cualquier marco de prueba utilizando la clase unittest.TraceTracker. Sin embargo, le recomiendo que evite usarlo para probar todos de su código, ya que aún debe tratar de escribir su código para que cada unidad de traducción pueda probarse aisladamente sin burlarse. A veces eso no es posible sin embargo.

Aquí es un ejemplo (no probado) de dicha prueba usando minimock y unittest:

# tests/test_foo.py 
import minimock 
import unittest 

import foo 

class FooTest(unittest2.TestCase): 
    def setUp(self): 
     # Track all calls into our mock objects. If we don't use a TraceTracker 
     # then all output will go to stdout, but we want to capture it. 
     self.tracker = minimock.TraceTracker() 

    def tearDown(self): 
     # Restore all objects in global module state that minimock had 
     # replaced. 
     minimock.restore() 

    def test_bar(self): 
     # foo.bar invokes urllib2.urlopen, and then calls read() on the 
     # resultin file object, so we'll use minimock to create a mocked 
     # urllib2. 
     urlopen_result = minimock.Mock('urlobject', tracker=self.tracker) 
     urlopen_result.read = minimock.Mock(
      'urlobj.read', tracker=self.tracker, returns='OMG') 
     foo.urllib2.urlopen = minimock.Mock(
      'urllib2.urlopen', tracker=self.tracker, returns=urlopen_result) 

     # Now when we call foo.bar(URL) and it invokes 
     # *urllib2.urlopen(URL).read()*, it will not actually send a request 
     # to URL, but will instead give us back the dummy response body 'OMG', 
     # which it then returns. 
     self.assertEquals(foo.bar('http://example.com/foo'), 'OMG') 

     # Now we can get trace info from minimock to verify that our mocked 
     # urllib2 was used as intended. self.tracker has traced our calls to 
     # *urllib2.urlopen()* 
     minimock.assert_same_trace(self.tracker, """\ 
Called urllib2.urlopen('http://example.com/foo) 
Called urlobj.read() 
Called urlobj.close()""") 

Las pruebas unitarias no deben ser los únicos tipos de pruebas que escribe sin embargo. Sin duda son útiles y la OMI es extremadamente importante si planea mantener este código por un período prolongado de tiempo. Hacen más fácil la refactorización y ayudan a detectar regresiones, pero en realidad no evalúan la interacción entre varios componentes y cómo interactúan (si lo haces bien).

Cuando empiezo a llegar al punto en el que tengo un producto mayormente terminado con una cobertura de prueba decente que pretendo lanzar, me gusta escribir al menos una prueba de integración que ejecute el programa completo en un entorno aislado.

He tenido mucho éxito con esto en mi proyecto actual. Tenía alrededor del 80% de cobertura de pruebas unitarias, y el resto del código era similar al análisis de argumentos, el envío de comandos y el estado de aplicación de nivel superior, que es difícil de cubrir en pruebas unitarias. Este programa tiene muchas dependencias externas, afecta a una docena de servicios web diferentes e interactúa con aproximadamente 6.000 máquinas en producción, por lo que ejecutarlo de manera aislada resultó algo difícil.

Terminé escribiendo una prueba de integración que engendra un servidor WSGI escrito con eventlet y webob que simula todos los servicios con los que mi programa interactúa en producción. A continuación, el mono de prueba de integración revisa nuestro web service client library para interceptar todas las solicitudes HTTP y enviarlas a la aplicación WSGI. Después de hacerlo, carga un archivo de estado que contiene una instantánea serializada del estado del clúster e invoca la aplicación llamando a su función main(). Ahora todos los servicios externos con los que mi programa interactúa son simulados, de modo que puedo ejecutar mi programa tal como se ejecutaría en producción de manera repetible.

0

Lo importante que debe recordar acerca de los doctests es que las pruebas se basan en comparaciones de cadenas, y la forma en que los números se representan como cadenas variará en diferentes plataformas e incluso en diferentes intérpretes de Python.

La mayor parte de mi trabajo se ocupa de cálculos, así que uso doctests solo para probar mis ejemplos y mi cadena de versión. Puse algunos en el __init__.py ya que aparecerán como la portada de mi documentación API generada por epydoc.

Uso nose para probar, aunque estoy muy interesado en ver los últimos cambios en py.test.

Cuestiones relacionadas