Comment puis-je implémenter un framework de test de régression simple avec Make? (J'utilise GNU Make, si cela importe.)
Mon makefile actuel ressemble à ceci (modifié pour plus de simplicité):
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)
J'aimerais avoir un ensemble de tests de régression, par exemple, expr.in
tester une "bonne" expression & unrecognized.in
en tester une "mauvaise", avec expr.cmp
& unrecognized.cmp
étant la sortie attendue pour chacun. Le test manuel ressemblerait à ceci:
$ 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
J'ai pensé ajouter un ensemble de règles au makefile ressemblant à ceci:
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]
Mes questions:
• Que dois-je mettre dans les espaces réservés [quelque chose]?
• Existe-t-il un moyen de remplacer le message de diff
par un message disant: "Échec du test expr
"?
Votre approche originale, comme indiqué dans la question, est la meilleure. Chacun de vos tests se présente sous la forme d'une paire d'entrées et de sorties attendues. Make est tout à fait capable de parcourir ces derniers et d'exécuter les tests; il n'est pas nécessaire d'utiliser une boucle Shell for
. En fait, en faisant cela, vous perdez la possibilité d'exécuter vos tests en parallèle et vous créez du travail supplémentaire pour nettoyer les fichiers temporaires (qui ne sont pas nécessaires).
Voici une solution (en utilisant bc comme exemple):
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 solution répond directement à vos questions d'origine:
$<
Et $(Word 2, $?)
correspondant aux prérequis %.test-in
Et %.test-cmp
Respectivement. Contrairement aux commentaires @reinierpost, les fichiers temporaires ne sont pas nécessaires.echo
.make -k
Pour exécuter tous les tests indépendamment du fait qu'un test individuel échoue ou réussisse.make -k all
Ne s'exécutera que si tous les tests réussissent.Nous évitons d'énumérer chaque test manuellement lors de la définition de la variable all-tests
En tirant parti de la convention de dénomination des fichiers (*.test-in
) Et des fonctions GNU make pour le fichier noms . En bonus, cela signifie que la solution évolue à des dizaines de milliers de tests hors de la boîte, car la longueur des variables est illimité dans GNU make C'est mieux que la solution basée sur Shell qui tombera une fois que vous aurez frappé le système d'exploitation limite de ligne de commande .
Créez un script de testeur qui prend un nom de test et déduit le nom de fichier d'entrée, le nom de fichier de sortie et les données de smaple à partir de cela:
#!/bin/sh
set -e
jscheme < $1.in > $1.out 2>&1
diff -q $1.out $1.cmp
Ensuite, dans votre Makefile
:
TESTS := expr unrecognised
.PHONY: test
test:
for test in $(TESTS); do bash test-runner.sh $$test || exit 1; done
Vous pouvez également essayer d'implémenter quelque chose comme automake
framework de test simple .
Ce que j'ai fini ressemble à ceci:
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
Il est basé sur l'idée de Jack Kelly, avec le conseil de Jonathan Leffler inclus.
Je vais répondre à votre question sur le diff. Tu peux faire:
diff fichier1 fichier2>/dev/null || écho Test bla bla échoué> & 2
bien que vous souhaitiez peut-être utiliser cmp au lieu de diff.
Sur une autre note, vous pourriez trouver utile d'aller de l'avant et de franchir le pas et d'utiliser Automake. Votre Makefile.am (dans son intégralité) ressemblera à:
bin_PROGRAMS = jscheme jscheme_SOURCES = jscheme.c utility.c model.c read.c eval.c print.c jscheme.h TESTS = script de test
et vous obtiendrez gratuitement de nombreuses cibles vraiment sympas, y compris un cadre de test assez complet.