2009-06-09 12 views
58

Casi todos los productos en los que he trabajado a lo largo de los años han implicado cierto nivel de scripts de shell (o archivos por lotes, PowerShell, etc., en Windows). A pesar de que escribimos la mayor parte del código en Java o C++, siempre parecía haber algunas tareas de integración o instalación que se realizaban mejor con un script de shell.Pruebas unitarias para scripts de shell

Los scripts de shell se vuelven parte del código enviado y, por lo tanto, deben probarse como el código compilado. ¿Alguien tiene experiencia con algunos de los marcos de prueba de unidad de script de shell que están disponibles, como shunit2? Principalmente estoy interesado en scripts de shell de Linux por ahora; Me gustaría saber qué tan bien el arnés de prueba duplica la funcionalidad y la facilidad de uso de otros marcos xUnit, y qué tan fácil es integrarlo con sistemas de construcción continua como CruiseControl o Hudson.

+1

También puede comprobar bashtest util: https: // github.com/pahaz/bashtest (es una forma sencilla de escribir pruebas de bash) – pahaz

+0

Roundup formaliza algunas tareas/etiquetas para usted. Una vez que superas la barrera del aprendizaje, es bastante útil. Personalmente, me gusta más el enfoque de haridsv, porque no requiere que instale otro paquete. He aplicado este enfoque a las pruebas de shell y python. – todo

+1

Verifique esta visión general de casi todas las herramientas posibles: https://medium.com/wemake-services/testing-bash-applications-85512e7fe2de – sobolevn

Respuesta

42

Estoy usando shunit2 para scripts de shell relacionados con una aplicación web Java/Ruby en un entorno Linux. Ha sido fácil de usar, y no es una gran diferencia con respecto a otros marcos xUnit.

No he probado la integración con climatizador o Hudson/Jenkins, pero en la implementación de la integración continua a través de otros medios que he encontrado con estos temas:

  • El estado de salida: Cuando un conjunto de pruebas falla, no se emplea shunit2 un estado de salida distinto de cero para comunicar el error. Por lo tanto, debe analizar la salida de shunit2 para determinar la aprobación/falla de un conjunto, o cambiar el comportamiento de shunit2 como lo esperan algunos marcos de integración continuos, comunicando pasa/falla a través del estado de salida.
  • Registros XML: shunit2 no produce un registro XML de resultados de estilo JUnit.
+0

Pete, estoy muy cerca de lanzar una biblioteca de prueba unitaria que funciona para bash y ksh, muy simple de usar. ¿Puede enviarme un enlace al registro XML de estilo Junit en algún lugar para que pueda ver lo que contiene? ¿Desea también el estado de salida para una sola prueba de falla o al final cuando se completa, si> 0 prueba falla la salida 1? La forma en que lo hago ahora es que hay una función a la que puede llamar para obtener el número de pruebas que pasaron o fallaron. –

+0

@EthanPost Ya no uso/requiero log XML. Puede encontrar ayuda haciendo búsquedas en Google para cosas como "xunit xml format". Cosas como esta: https://xunit.github.io/docs/format-xml-v2.html –

16

Resumen: http://bmizerany.github.com/roundup/

Hay un enlace a un artículo en el README que explica en detalle.

+1

resumen también recomienda [concurso] (https://github.com/citrusbyte/contest) –

20

Roundup por @ Blake-mizerany suena muy bien, y yo debería hacer uso de ella en el futuro, pero aquí es mi enfoque "hombre pobre" para la creación de pruebas unitarias:

  • independiente todo comprobable como función.
  • Mueva las funciones a un archivo externo, digamos functions.sh y source en la secuencia de comandos. Puede usar source `dirname $0`/functions.sh para este propósito.
  • Al final de functions.sh, incrustar los casos de prueba en el siguiente si la condición:

    if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then 
    fi 
    
  • Sus pruebas son llamadas literales a las funciones seguido de controles simples para los códigos de salida y valores de variables. Me gustaría añadir una función de utilidad tan simple como el siguiente para que sea fácil de escribir:

    function assertEquals() 
    { 
        msg=$1; shift 
        expected=$1; shift 
        actual=$1; shift 
        if [ "$expected" != "$actual" ]; then 
         echo "$msg EXPECTED=$expected ACTUAL=$actual" 
         exit 2 
        fi 
    } 
    
  • Por último, ejecute functions.sh directamente a ejecutar las pruebas.

Este es un ejemplo para mostrar el enfoque:

#!/bin/bash 
    function adder() 
    { 
     return $(($1+$2)) 
    } 

    (
     [[ "${BASH_SOURCE[0]}" == "${0}" ]] || exit 0 
     function assertEquals() 
     { 
      msg=$1; shift 
      expected=$1; shift 
      actual=$1; shift 
      /bin/echo -n "$msg: " 
      if [ "$expected" != "$actual" ]; then 
       echo "FAILED: EXPECTED=$expected ACTUAL=$actual" 
      else 
       echo PASSED 
      fi 
     } 

     adder 2 3 
     assertEquals "adding two numbers" 5 $? 
    ) 
+1

Agradable, gracias - Realmente como el enfoque de programación estructurada para los scripts de shell. –

+0

Muy buena observación allí: 'Separa todo lo que se pueda probar como una función'. Es importante incluso si no (todavía) escribe una prueba para ello. Es un factor importante para mejorar la legibilidad del código. Hace un par de años comencé a escribir mi guión (ksh) de acuerdo con este principio. Escribe todo como una función. –

+0

@HenkLangeveld ¿No saldrá la 'salida 0' porque el" fuentee "(la fuente de esto) también? Creo que estás buscando 'regresar' aquí. – haridsv

6

Además de roundup y shunit2 mi visión general de las herramientas de pruebas unitarias Shell también incluye assert.sh y shelltestrunner.

En general, estoy de acuerdo con la crítica del autor de resumen de shunit2 (en parte, subjetiva), por lo que excluí shunit2 después de mirar la documentación y ejemplos. Aunque, parecía familiar tener alguna experiencia con jUnit.

En mi opinión, shelltestrunner es la herramienta más original que he analizado, ya que usa una sintaxis declarativa simple para la definición de caso de prueba. Como de costumbre, cualquier nivel de abstracción ofrece cierta comodidad a costa de cierta flexibilidad. Aunque la simplicidad es atractiva, encontré que la herramienta es demasiado limitada para el caso que tuve, principalmente debido a la falta de una manera de definir las acciones de configuración/desvío (por ejemplo, manipular archivos de entrada antes de una prueba, eliminar archivos de estado después de una prueba , etc.)

al principio estaba un poco confundido que assert.sh sólo permite afirmar la producción o el código de salida, mientras que tanto necesitaba. El tiempo suficiente para escribir un par de casos de prueba usando el rodeo. Pero pronto encontré inconveniente el modo set -e del rodeo ya que se espera un estado de salida distinto de cero en algunos casos como medio para comunicar el resultado además de stdout, lo que hace que el caso de prueba falle en dicho modo. One of the samples muestra la solución:

status=$(set +e ; rup roundup-5 >/dev/null ; echo $?) 

Pero lo que si necesito tanto el estado de salida distinto de cero y la salida? Pude, por supuesto, set +e antes de la invocación y set -e después o set +e para todo el caso de prueba. Pero eso va en contra del principio del rodeo "Everything is an Assertion". Entonces sentí que comenzaba a trabajar contra la herramienta.

Para entonces me he dado cuenta "inconveniente" de la assert.sh de permitir sólo a valer ya sea el código de salida o salida es en realidad un problema no como acabo puedo pasar en test con una expresión compuesta como esta

output=$($tested_script_with_args) 
status=$? 
expected_output="the expectation" 
assert_raises "test \"$output\" = \"$expected_output\" -a $status -eq 2" 

Como mis necesidades eran muy básico (ejecutar una serie de pruebas, muestre que todo ha ido bien o qué no), me gustó la simplicidad de assert.sh, así que eso es lo que elegí.

2

Después de buscar un marco de prueba de unidad sencilla para la cáscara que podría generar resultados XML de Jenkins y en realidad no encontrar nada, me escribió una.

Está en sourceforge - el nombre del proyecto es jshu.

http://sourceforge.net/projects/jshu

23

Se pregunta por qué nadie menciona BATS. Está actualizado y TAP -compliant.

Describe:

#!/usr/bin/env bats 

@test "addition using bc" { 
    result="$(echo 2+2 | bc)" 
    [ "$result" -eq 4 ] 
} 

Run:

$ bats addition.bats 
✓ addition using bc 

1 tests, 0 failures 
+1

+1 para BATS! A juzgar por sus métricas github (12 colaboradores, casi 2000 estrellas), esta es la herramienta que la mayoría de la gente elige como corredor de pruebas bash xUnit. –

+1

+1: He usado BATS hace un tiempo y no estaba completamente abrumado. Encontré este excelente (¿independiente?) [Documento de inicio] (https://medium.com/@pimterry/testing-your-shell-scripts-with-bats-abfca9bdc5b9) hoy, lo seguí y ahora estoy totalmente vendido en BATS . – ssc