2009-06-28 9 views
5

Estoy aprendiendo Python y he estado tratando de entender más sobre los detalles del módulo unittest de Python. La documentación incluye los siguientes:Con Python unittest, ¿cómo creo y uso un "objeto invocable que devuelve un conjunto de pruebas"?

Para la facilidad de las pruebas de funcionamiento, ya que veremos más adelante, es una buena idea para proporcionan en cada módulo de prueba de un objeto invocable que devuelve una prueba de pre-construidos suite:

def suite(): 
    suite = unittest.TestSuite() 
    suite.addTest(WidgetTestCase('testDefaultSize')) 
    suite.addTest(WidgetTestCase('testResize')) 
    return suite 

Por lo que yo puedo decir, no se explica el propósito de hacer esto. Además, no pude averiguar cómo se usaría dicho método. He intentado varias cosas sin éxito (aparte de aprender acerca de los mensajes de error que tengo):

import unittest 

def average(values): 
    return sum(values)/len(values) 

class MyTestCase(unittest.TestCase): 
    def testFoo(self): 
     self.assertEqual(average([10,100]),55) 

    def testBar(self): 
     self.assertEqual(average([11]),11) 

    def testBaz(self): 
     self.assertEqual(average([20,20]),20) 

    def suite(): 
     suite = unittest.TestSuite() 
     suite.addTest(MyTestCase('testFoo')) 
     suite.addTest(MyTestCase('testBar')) 
     suite.addTest(MyTestCase('testBaz')) 
     return suite 

if __name__ == '__main__': 
    # s = MyTestCase.suite() 
    # TypeError: unbound method suite() must be called 
    # with MyTestCase instance as first argument 

    # s = MyTestCase.suite(MyTestCase()) 
    # ValueError: no such test method in <class '__main__.MyTestCase'>: runTest 

    # s = MyTestCase.suite(MyTestCase('testFoo')) 
    # TypeError: suite() takes no arguments (1 given) 

El siguiente "trabajaron", pero parece torpe y se requiere que cambie el método de firma de suite() a 'def suite(self):'.

s = MyTestCase('testFoo').suite() 
unittest.TextTestRunner().run(s) 

Respuesta

6

El primer mensaje de error que tiene es significativo y explica mucho.

print MyTestCase.suite # <unbound method MyTestCase.suite> 

Sin consolidar. Significa que no puede llamarlo a menos que lo vincule a una instancia. En realidad es el mismo para MyTestCase.run:

print MyTestCase.run # <unbound method MyTestCase.run> 

Tal vez por ahora no entiende por qué no se puede llamar suite, pero por favor, dejar a un lado por ahora. ¿Tratarías de llamar al run en la clase, como arriba? Algo así como:

MyTestCase.run() # ? 

Probablemente no, ¿verdad? No tiene sentido escribir esto, y no funcionará, porque run es un método de instancia y necesita una instancia de self para trabajar. Bueno, parece que Python "entiende" suite de la misma manera que entiende run, como un método independiente.

Veamos por qué:

Si se intenta poner el método suite fuera del ámbito de la clase, y lo definen como una función global, simplemente funciona:

import unittest 

def average(values): 
    return sum(values)/len(values) 

class MyTestCase(unittest.TestCase): 
    def testFoo(self): 
     self.assertEqual(average([10,100]),55) 

    def testBar(self): 
     self.assertEqual(average([11]),11) 

    def testBaz(self): 
     self.assertEqual(average([20,20]),20) 

def suite(): 
    suite = unittest.TestSuite() 
    suite.addTest(MyTestCase('testFoo')) 
    suite.addTest(MyTestCase('testBar')) 
    suite.addTest(MyTestCase('testBaz')) 
    return suite 

print suite() # <unittest.TestSuite tests=[<__main__.MyTestCase testMethod=testFoo>, <__main__.MyTestCase testMethod=testBar>, <__main__.MyTestCase testMethod=testBaz>]> 

pero no es así quiero fuera del ámbito de la clase, ya que desea llamar MyTestCase.suite()

probablemente pensó que desde suite era una especie de "estática", o una instancia independiente, no tiene sentido poner un argume self nt, ¿verdad? Correcto.

Pero si define un método dentro de una clase de Python, Python esperará que ese método tenga un argumento self como primer argumento. Solo omitir el argumento self no hace que su método static sea automáticamente. Cuando se desea definir un método de "estática", usted tiene que utilizar el staticmethod decorador:

@staticmethod 
def suite(): 
    suite = unittest.TestSuite() 
    suite.addTest(MyTestCase('testFoo')) 
    suite.addTest(MyTestCase('testBar')) 
    suite.addTest(MyTestCase('testBaz')) 
    return suite 

De esta manera Python no considera MyTestCase como un método de instancia, sino como una función:

print MyTestCase.suite # <function suite at 0x...> 

Y por supuesto, ahora puede llamar al MyTestCase.suite(), y eso funcionará como se esperaba.

if __name__ == '__main__': 
    s = MyTestCase.suite() 
    unittest.TextTestRunner().run(s) # Ran 3 tests in 0.000s, OK 
1

El documentation está diciendo suite() debería ser una función en el módulo, en lugar de un método en su clase. Parece ser simplemente una función de conveniencia para que pueda conjuntos de pruebas más adelante agregados para muchos módulos:

alltests = unittest.TestSuite([ 
    my_module_1.suite(), 
    my_module_2.suite(), 
]) 

Sus problemas con llamar a su función están todas relacionadas a que es un método en la clase, aún no escrita como método . El parámetro self es el "objeto actual" y es obligatorio para los métodos de ejemplo. (Por ejemplo, a.b(1, 2) es conceptualmente el mismo que b(a, 1, 2)). Si el método opera en la clase en lugar de instancias, lea aproximadamente classmethod. Si solo está agrupado con la clase por conveniencia, pero no funciona en la clase ni en las instancias, lea acerca de staticmethod. Ninguno de estos le ayudará particularmente a usar unittest, pero podrían ayudar a explicar por qué vio lo que hizo.

1

Una cosa que es importante tener en cuenta, nose es una herramienta que realmente simplifica las pruebas de funcionamiento. Le permite especificar exactamente qué pruebas ejecutar desde la línea de comandos, así como recorrer cada directorio y ejecutar cada prueba.

1

Como ya se mencionó, la documentación se refiere a suite() como un método en el módulo, y unittest (extrañamente) no parece tener ningún reconocimiento especial para este método, por lo que debe llamarlo explícitamente. Sin embargo, si usa una herramienta llamada "testoob", llama automáticamente al método suite() (si especifica el argumento defaultTest = "suite" a su main()) y agrega varias otras características sobre el paquete unittest base. También proporciona opciones para generar archivos XML que incluyen stdout y stderr recopilados de estas pruebas (que es una gran ventaja para las pruebas automatizadas) y también puede generar informes HTML (aunque necesitaría instalar paquetes adicionales). No pude encontrar una manera de descubrir automáticamente todas las pruebas que la nariz dice respaldar, por lo que la nariz es probablemente una mejor opción.

0

Sugeriría utilizar lo siguiente. Esto le evita ingresar manualmente todas las pruebas que agrega a medida que avanza.

def suite(): 
    suite = unittest.TestLoader().loadTestsFromTestCase(Your_Test_Case_Class) 
    return suite 

Esto le da la flexibilidad para ejecutar pruebas en el mismo módulo definiendo:

if __name__ == "__main__": 
    suite() 

Y si desea agrupar sus suites en otro módulo de test_suite.py es decir (por ejemplo), entonces se podría hacer mediante la siguiente manera:

nombre test_module importación importación unittest

if __name__=="__main__": 
    suite1=test_module_name.suite() 
    ... 
    ... 
    alltests = unittest.TestSuite([suite1,suite2]) 

Ahora cómo ejecutar sus pruebas.Yo generalmente uso la manera más sencilla de ejecutar mediante la ejecución de este comando en el nivel de paquete, y unittest descubre automáticamente las pruebas:

python -m unittest discover 

o

nosetests 

advertencia: unittest es X veces más rápido que nosetest , por lo tanto, depende de las preferencias de los desarrolladores, especialmente si han utilizado complementos de terceros y desea continuar usándolo.

Cuestiones relacionadas