Aplicar o "make check" ou o " make test`

Como posso implementar um simples quadro de testes de regressão com o Make? (Estou usando GNU Make, se isso importa.)

a minha makefile actual parece-se com isto (editada por simplicidade):

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)
Gostaria de ter um conjunto de testes de regressão, por exemplo., expr.in Testando uma expressão" boa "& unrecognized.in testando uma expressão" má", com expr.cmp & unrecognized.cmp sendo a saída esperada para cada um. Testes manuais seriam assim:

$ 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
Pensei em Adicionar um conjunto de regras a o makefile é parecido com isto.
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]

as minhas perguntas:
• O que é que eu ponho nos espaços?
• Existe uma maneira de substituir a mensagem de diff por uma mensagem dizendo: "teste expr falhou"?

Author: J. C. Salomon, 2011-02-08

4 answers

A sua abordagem original, tal como se afirma na pergunta, é a melhor. Cada um dos seus testes é na forma de um par de Entradas e Saídas esperadas. Make é bastante capaz de iterar através destes e executar os testes;não há necessidade de usar um loop shell for. Na verdade, ao fazer isso você está perdendo a oportunidade de executar seus testes em paralelo, e criando trabalho extra para si mesmo para limpar arquivos temporários (que não são necessários).

Aqui está uma solução (usando bc como um exemplo):
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."

A solução responde directamente às suas perguntas originais:

  • as substituições que procura são $< e $(word 2, $?) correspondentes aos pré-requisitos %.test-in e %.test-cmp respectivamente. Ao contrário do @reinierpost, os ficheiros temporários de comentários não são necessários.
  • a mensagem de diferenças é escondida e substituída por echo.
  • o makefile deve ser invocado com make -k para executar todos os testes, independentemente de um teste individual falhar ou suceder.
  • make -k all só funcionará se todos os testes forem bem sucedidos.

Evitamos enumerar cada teste manualmente ao definir a variável all-tests, alavancando a Convenção de nomenclatura de ficheiros (*.test-in) e as funções GNU make para nomes de ficheiros . Como um Bônus, isso significa que a solução escala para dezenas de milhares de testes fora da caixa, como o comprimento das variáveis é ilimitado em GNU make. Isto é melhor do que a solução baseada no shell que cairá sobre uma vez que você bater the operating system command line limit .

 10
Author: Richard Padley, 2017-12-09 17:53:23

Faça um programa de execução de testes que tome um nome de teste e infira o nome do ficheiro de entrada, o nome do ficheiro de saída e os dados do smaple a partir desse:

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

Então, no seu Makefile:

TESTS := expr unrecognised

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

Você também poderia tentar implementar algo como automake's quadro de testes simples.

 10
Author: Jack Kelly, 2011-12-13 20:51:47

O que eu acabei com Parece-se com isto:

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
É baseado na ideia do Jack Kelly, com a ponta do Jonathan Leffler incluída.
 3
Author: J. C. Salomon, 2011-02-10 22:37:52
Vou responder à tua pergunta sobre o diff. Você pode fazer:
diff file1 file2 > /dev/null || echo Test blah blah failed >&2

Apesar de poder querer usar cmp em vez de diff.

Por outro lado, pode ser útil ir em frente e tomar o mergulho e usar automake. A sua Makefile.am (na sua totalidade) vai parecer:
bin_PROGRAMS = jscheme
jscheme_SOURCES = jscheme.c utility.c model.c read.c eval.c print.c jscheme.h
TESTS = test-script
E você vai ter um monte de alvos realmente bonitos de graça, incluindo um quadro de testes bastante completo.
 2
Author: William Pursell, 2011-02-08 12:53:20