¿Pruebas unitarias de Python en Jenkins?

135

¿Cómo se consigue que Jenkins ejecute casos de Python unittest? ¿Es posible hacer una salida XML de estilo JUnit desde el unittestpaquete incorporado ?

erikbwork
fuente
1
Todas las respuestas suponen que desea iniciar los casos de prueba desde la línea de comandos. Pero si desea ejecutar las pruebas mediante programación, intente esto:import nose ; nose.runmodule() # aka nose.run(defaultTest=__name__)
MarkHu
1
En mi humilde opinión, la sugerencia simple 'py.test --junitxml results.xml test.py' responde mejor a la pregunta. 'yum install pytest' para instalar py.test. Luego puede ejecutar cualquier script python de unittest y obtener resultados de jUnit xml
gaoithe
1
@gaoithe que responde a la parte de jenkins, pero no cumple con el requisito de usar el módulo de prueba de unidad incorporado. En ese proyecto era un requisito dado.
erikbwork
@ erikb85 Cuando digo "ejecutar cualquier script de unittest python" me refiero a un script que utiliza el módulo unittest.
Gaoithe

Respuestas:

173

pruebas de muestra:

tests.py:

# tests.py

import random
try:
    import unittest2 as unittest
except ImportError:
    import unittest

class SimpleTest(unittest.TestCase):
    @unittest.skip("demonstrating skipping")
    def test_skipped(self):
        self.fail("shouldn't happen")

    def test_pass(self):
        self.assertEqual(10, 7 + 3)

    def test_fail(self):
        self.assertEqual(11, 7 + 3)

JUnit con pytest

ejecuta las pruebas con:

py.test --junitxml results.xml tests.py

resultados.xml:

<?xml version="1.0" encoding="utf-8"?>
<testsuite errors="0" failures="1" name="pytest" skips="1" tests="2" time="0.097">
    <testcase classname="tests.SimpleTest" name="test_fail" time="0.000301837921143">
        <failure message="test failure">self = &lt;tests.SimpleTest testMethod=test_fail&gt;

    def test_fail(self):
&gt;       self.assertEqual(11, 7 + 3)
E       AssertionError: 11 != 10

tests.py:16: AssertionError</failure>
    </testcase>
    <testcase classname="tests.SimpleTest" name="test_pass" time="0.000109910964966"/>
    <testcase classname="tests.SimpleTest" name="test_skipped" time="0.000164031982422">
        <skipped message="demonstrating skipping" type="pytest.skip">/home/damien/test-env/lib/python2.6/site-packages/_pytest/unittest.py:119: Skipped: demonstrating skipping</skipped>
    </testcase>
</testsuite>

JUnit con nariz

ejecuta las pruebas con:

nosetests --with-xunit

nosetests.xml:

<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="nosetests" tests="3" errors="0" failures="1" skip="1">
    <testcase classname="tests.SimpleTest" name="test_fail" time="0.000">
        <failure type="exceptions.AssertionError" message="11 != 10">
            <![CDATA[Traceback (most recent call last):
File "/opt/python-2.6.1/lib/python2.6/site-packages/unittest2-0.5.1-py2.6.egg/unittest2/case.py", line 340, in run
testMethod()
File "/home/damien/tests.py", line 16, in test_fail
self.assertEqual(11, 7 + 3)
File "/opt/python-2.6.1/lib/python2.6/site-packages/unittest2-0.5.1-py2.6.egg/unittest2/case.py", line 521, in assertEqual
assertion_func(first, second, msg=msg)
File "/opt/python-2.6.1/lib/python2.6/site-packages/unittest2-0.5.1-py2.6.egg/unittest2/case.py", line 514, in _baseAssertEqual
raise self.failureException(msg)
AssertionError: 11 != 10
]]>
        </failure>
    </testcase>
    <testcase classname="tests.SimpleTest" name="test_pass" time="0.000"></testcase>
    <testcase classname="tests.SimpleTest" name="test_skipped" time="0.000">
        <skipped type="nose.plugins.skip.SkipTest" message="demonstrating skipping">
            <![CDATA[SkipTest: demonstrating skipping
]]>
        </skipped>
    </testcase>
</testsuite>

JUnit con nariz2

Tendría que usar el nose2.plugins.junitxmlcomplemento. Puede configurar nose2con un archivo de configuración como lo haría normalmente, o con la --pluginopción de línea de comandos.

ejecuta las pruebas con:

nose2 --plugin nose2.plugins.junitxml --junit-xml tests

nose2-junit.xml:

<testsuite errors="0" failures="1" name="nose2-junit" skips="1" tests="3" time="0.001">
  <testcase classname="tests.SimpleTest" name="test_fail" time="0.000126">
    <failure message="test failure">Traceback (most recent call last):
  File "/Users/damien/Work/test2/tests.py", line 18, in test_fail
    self.assertEqual(11, 7 + 3)
AssertionError: 11 != 10
</failure>
  </testcase>
  <testcase classname="tests.SimpleTest" name="test_pass" time="0.000095" />
  <testcase classname="tests.SimpleTest" name="test_skipped" time="0.000058">
    <skipped />
  </testcase>
</testsuite>

JUnit con unittest-xml-reporting

Agregue lo siguiente a tests.py

if __name__ == '__main__':
    import xmlrunner
    unittest.main(testRunner=xmlrunner.XMLTestRunner(output='test-reports'))

ejecuta las pruebas con:

python tests.py

test-reports / TEST-SimpleTest-20131001140629.xml:

<?xml version="1.0" ?>
<testsuite errors="1" failures="0" name="SimpleTest-20131001140629" tests="3" time="0.000">
    <testcase classname="SimpleTest" name="test_pass" time="0.000"/>
    <testcase classname="SimpleTest" name="test_fail" time="0.000">
        <error message="11 != 10" type="AssertionError">
<![CDATA[Traceback (most recent call last):
  File "tests.py", line 16, in test_fail
    self.assertEqual(11, 7 + 3)
AssertionError: 11 != 10
]]>     </error>
    </testcase>
    <testcase classname="SimpleTest" name="test_skipped" time="0.000">
        <skipped message="demonstrating skipping" type="skip"/>
    </testcase>
    <system-out>
<![CDATA[]]>    </system-out>
    <system-err>
<![CDATA[]]>    </system-err>
</testsuite>
dnozay
fuente
44
+1 para la sugerencia simple 'py.test --junitxml results.xml test.py'. 'yum install pytest' para instalar py.test. Luego puede ejecutar cualquier script de python unittest y obtener resultados jUnit xml.
Gaoithe
1
Si desea utilizar unittest-xml-reporting y beneficiarse de la función Test Discovery , puede poner unittest.main(module=None, testRunner=xmlrunner.XMLTestRunner(output='test-reports')).
Rosberg Linhares
@RosbergLinhares ¿por qué necesita module=Noneusar Test Discovery? Funciona exactamente como se describe en la respuesta unittest.main(testRunner=xmlrunner.XMLTestRunner(output='test-reports')).
acm
@RosbergLinhares, durante el descubrimiento de prueba, los módulos solo se importan pero no se ejecutan. Entonces, ¿cómo se supone que alguna de esas soluciones funciona con el descubrimiento? Lo acabo de probar, nada de eso funciona. ¿O me estoy perdiendo algo?
Konstantin el
20

Yo segundo usaría la nariz. Los informes XML básicos ahora están integrados. Solo use la opción de línea de comando --with-xunit y producirá un archivo nosetests.xml. Por ejemplo:

pruebas de nariz --with-xunit

A continuación, agregue una acción posterior a la compilación "Publicar informe de resultados de la prueba JUnit" y complete el campo "XML de informe de prueba" con nosetests.xml (suponiendo que ejecutó pruebas de nariz en $ WORKSPACE).

Joshua D. Boyd
fuente
11

Puede instalar el paquete unittest-xml-reporting para agregar un corredor de prueba que genere XML al incorporado unittest.

Usamos pytest , que tiene una salida XML incorporada (es una opción de línea de comando).

De cualquier manera, la ejecución de las pruebas unitarias se puede realizar ejecutando un comando de shell.

Dave Bacher
fuente
4

Usé pruebas de nariz. Hay complementos para generar el XML para Jenkins

John La Rooy
fuente
2
python -m pytest --junit-xml=pytest_unit.xml source_directory/test/unit || true # tests may fail

Ejecute esto como shell desde jenkins, puede obtener el informe en pytest_unit.xml como artefacto.

Rajib Mitra
fuente