test serp seomofo scan google description checker check testing makefile gnu-make regression-testing

testing - serp - seomofo title



Implementando `make check` o` make test` (4)

Haga un script de corredor de prueba que tome un nombre de prueba e infiera el nombre de archivo de entrada, el nombre de archivo de salida y los datos de smaple de eso:

#!/bin/bash set -e jscheme < $1.in > $1.out 2>&1 diff -q $1.out $1.cmp

Luego, en tu Makefile :

TESTS := expr unrecognised .PHONY: test test: for test in $(TESTS); do bash test-runner.sh $$test || exit 1; done

También puedes intentar implementar algo como el marco de prueba simple de automake .

¿Cómo puedo implementar un marco de prueba de regresión simple con Make? (Estoy usando GNU Make, si eso importa).

Mi makefile actual se ve algo como esto (editado para simplificar):

OBJS = jscheme.o utility.o model.o read.o eval.o print.o %.o : %.c jscheme.h gcc -c -o $@ $< jscheme : $(OBJS) gcc -o $@ $(OBJS) .PHONY : clean clean : -rm -f jscheme $(OBJS)

Me gustaría tener un conjunto de pruebas de regresión, por ejemplo , expr.in probar una expresión "buena" y unrecognized.in expr.cmp una "mala", con expr.cmp y unrecognized.cmp como el resultado esperado para cada una. Las pruebas manuales se verían así:

$ jscheme < expr.in > expr.out 2>&1 $ jscheme < unrecognized.in > unrecognized.out 2>&1 $ diff -q expr.out expr.cmp # identical $ diff -q unrecognized.out unrecognized.cmp Files unrecognized.out and unrecognized.cmp differ

Pensé en agregar un conjunto de reglas al makefile buscando algo como esto:

TESTS = expr.test unrecognized.test .PHONY test $(TESTS) test : $(TESTS) %.test : jscheme %.in %.cmp jscheme < [something.in] > [something.out] 2>&1 diff -q [something.out] [something.cmp]

Mis preguntas:
• ¿Qué pongo en los marcadores de posición [algo]?
• ¿Hay alguna manera de reemplazar el mensaje de diff con un mensaje que diga “Falló la prueba expr ”?


Lo que acabé con se ve así:

TESTS = whitespace list boolean character / literal fixnum string symbol quote .PHONY: clean test test: $(JSCHEME) for t in $(TESTS); do / $(JSCHEME) < test/$$t.ss > test/$$t.out 2>&1; / diff test/$$t.out test/$$t.cmp > /dev/null || / echo Test $$t failed >&2; / done

Se basa en la idea de Jack Kelly, con la sugerencia de Jonathan Leffler incluida.


Su enfoque original, como se indica en la pregunta, es el mejor. Cada una de sus pruebas tiene la forma de un par de entradas y salidas esperadas. Make es bastante capaz de iterar a través de estos y ejecutar las pruebas; no hay necesidad de usar un shell for bucle. De hecho, al hacer esto, está perdiendo la oportunidad de ejecutar sus pruebas en paralelo y creando un trabajo adicional para limpiar archivos temporales (que no son necesarios).

Aquí hay una solución (usando bc como ejemplo):

SHELL := /bin/bash all-tests := $(addsuffix .test, $(basename $(wildcard *.test-in))) .PHONY : test all %.test BC := /usr/bin/bc test : $(all-tests) %.test : %.test-in %.test-cmp $(BC) @$(BC) <$< 2>&1 | diff -q $(word 2, $?) - >/dev/null || / (echo "Test $@ failed" && exit 1) all : test @echo "Success, all tests passed."

La solución aborda directamente sus preguntas originales:

  • Los marcadores de posición que busca son $< y $(word 2, $?) Correspondientes a los requisitos previos %.test-in y %.test-cmp respectivamente. Contrariamente a los comentarios de @reinierpost, los archivos temporales no son necesarios.
  • El mensaje de diff se oculta y se reemplaza con echo .
  • El makefile debe invocarse con make -k para ejecutar todas las pruebas independientemente de si una prueba individual falla o tiene éxito.
  • make -k all solo se ejecutará si todas las pruebas tienen éxito.

Evitamos enumerar cada prueba manualmente cuando definimos la variable de all-tests al aprovechar la convención de nomenclatura de archivos ( *.test-in ) y las funciones de GNU make para los nombres de archivos . Como beneficio adicional, esto significa que la solución se amplía a decenas de miles de pruebas fuera de la caja, ya que la longitud de las variables es unlimited en la unlimited de GNU. Esto es mejor que la solución basada en shell que se caerá una vez que llegue al límite de la línea de comandos del sistema operativo.


Voy a abordar sólo su pregunta acerca de diff. Tu puedes hacer:

diff file1 file2 > /dev/null || echo Test blah blah failed >&2

aunque es posible que desee utilizar cmp en lugar de diff.

En otra nota, puede que le resulte útil seguir adelante y dar el paso y usar automake. Tu Makefile.am (en su totalidad) se verá así:

bin_PROGRAMS = jscheme jscheme_SOURCES = jscheme.c utility.c model.c read.c eval.c print.c jscheme.h TESTS = test-script

y obtendrás una gran cantidad de objetivos realmente buenos gratis, incluido un marco de prueba bastante completo.