linux - pasar - Pruebas unitarias para guiones de shell
script bash linux ejemplos (7)
Además de roundup y shunit2 mi descripción general de las herramientas de prueba de unidad de shell también incluía assert.sh y shelltestrunner .
En general, estoy de acuerdo con la crítica del autor de resumen a shunit2 (en parte, subjetiva), por lo que excluí shunit2 después de consultar la documentación y los 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 es habitual, 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 de que assert.sh solo permite afirmar el estado de salida o salida, mientras que yo necesitaba ambos. 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 el estado de salida distinto de cero en algunos casos como un medio para comunicar el resultado además de stdout, lo que hace que el caso de prueba falle en dicho modo. Una de las muestras muestra la solución:
status=$(set +e ; rup roundup-5 >/dev/null ; echo $?)
Pero, ¿qué ocurre si necesito tanto el estado de salida distinto de cero como el resultado? Podría, 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 "Todo es una afirmación" . Entonces sentí que comenzaba a trabajar contra la herramienta.
Para entonces, me he dado cuenta de que el "inconveniente" de assert.sh de permitir solo afirmar el estado de salida o la salida no es un problema ya que puedo pasar la 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 realmente básicas (ejecutar un conjunto de pruebas, mostrar que todo fue bien o que falló), me gustó la simplicidad de assert.sh, así que eso es lo que elegí.
Prácticamente todos los productos en los que he trabajado a lo largo de los años han incluido algún 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.
Por lo tanto, los scripts de shell se vuelven parte del código enviado y, por lo tanto, deben probarse al igual que 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.
Debes probar assert.sh lib, muy práctico, fácil de usar
local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent!
Después de buscar un marco de prueba de unidad simple para shell que pudiera generar resultados xml para Jenkins y no encontrar realmente nada, escribí uno.
Está en sourceforge - el nombre del proyecto es jshu.
El rodeo de @ blake-mizerany suena genial, y debería usarlo en el futuro, pero este es mi enfoque de "pobre hombre" para crear pruebas unitarias:
- Separa todo lo que se pueda probar como una función.
- Mueva las funciones a un archivo externo, digamos
functions.sh
ysource
en el script. Puede usarsource `dirname $0`/functions.sh
para este propósito. Al final de
functions.sh
, incruste sus casos de prueba en la siguiente condición if:if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then fi
Sus pruebas son llamadas literales a las funciones seguidas por comprobaciones simples para códigos de salida y valores variables. Me gusta agregar una función de utilidad simple como la siguiente para que sea más fácil 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 }
Finalmente, ejecute
functions.sh
directamente para ejecutar las pruebas.
Aquí hay una muestra 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 $?
)
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 tratado de integrarme con CruiseControl o Hudson / Jenkins, pero al implementar la integración continua por otros medios me he encontrado con estos problemas:
- Estado de salida: cuando falla un conjunto de pruebas, shunit2 no utiliza 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.
Resumen: http://bmizerany.github.com/roundup/
Hay un enlace a un artículo en el README que lo explica en detalle.