Wdrożenie `make check " lub " make test`

Jak zaimplementować prosty framework testu regresji za pomocą Make? (Używam GNU Make, jeśli to ma znaczenie.)

Mój obecny makefile wygląda mniej więcej tak (edytowany dla uproszczenia):

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)

Chciałbym mieć zestaw testów regresyjnych, np., expr.in testowanie wyrażenia "dobrego" & unrecognized.in testowanie wyrażenia "złego", z expr.cmp & unrecognized.cmp jako oczekiwany wynik dla każdego. Testy manualne wyglądałyby tak:

$ 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

Pomyślałem, aby dodać zestaw zasad do makefile wygląda tak:

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]
Moje pytania:
* Co umieścić w [coś] placeholders?
• Czy istnieje sposób na zastąpienie wiadomości z diff Komunikatem "Test expr nie powiódł się"?
Author: J. C. Salomon, 2011-02-08

4 answers

Twoje oryginalne podejście, jak wspomniano w pytaniu, jest najlepsze. Każdy z Twoich testów ma formę pary oczekiwanych wejść i wyjść. Make jest całkiem zdolny do iteracji i uruchamiania testów; nie ma potrzeby używania pętli Powłoki for. W rzeczywistości w ten sposób tracisz możliwość równoległego uruchamiania testów i tworzenia dodatkowej pracy dla siebie, aby oczyścić pliki tymczasowe (które nie są potrzebne).

Oto rozwiązanie (używając bc jako przykład):

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."

Rozwiązanie bezpośrednio odpowiada na twoje oryginalne pytania:

  • symbole zastępcze, których szukasz, to $< i $(word 2, $?), odpowiadające odpowiednio wymogom wstępnym %.test-in i %.test-cmp. W przeciwieństwie do komentarza @ reinierpost pliki tymczasowe nie są potrzebne.
  • wiadomość diff jest ukryta i zastąpiona przez echo.
  • plik makefile powinien być wywoływany z make -k, aby uruchomić wszystkie testy niezależnie od tego, czy pojedynczy test się nie powiedzie lub / align = "left" /
  • make -k all będzie działać tylko wtedy, gdy wszystkie testy się powiodą.

Unikamy ręcznego wyliczania każdego testu podczas definiowania zmiennej all-tests, wykorzystując konwencję nazewnictwa plików (*.test-in) i funkcje GNU make dla nazw plików. Jako bonus oznacza to, że rozwiązanie skaluje się do dziesiątek tysięcy testów po wyjęciu z pudełka, ponieważ długość zmiennych jest nieograniczona W GNU make. Jest to lepsze niż rozwiązanie oparte na powłoce, które spadnie po trafieniu system operacyjny limit linii poleceń .

 10
Author: Richard Padley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-09 17:53:23

Tworzy skrypt runnera testowego, który pobiera nazwę testu i wyprowadza z niego dane wejściowe, wyjściowe i smaple:

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

Wtedy w twoim Makefile:

TESTS := expr unrecognised

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

Możesz również spróbować zaimplementować coś w rodzaju automake'S simple test framework .

 10
Author: Jack Kelly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-13 20:51:47

To z czym skończyłem wygląda tak:

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
Jest oparty na pomyśle Jacka Kelly ' ego, z dołączoną wskazówką Jonathana Lefflera.
 3
Author: J. C. Salomon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-10 22:37:52

Odpowiem na twoje pytanie o diff. Można zrobić:

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

Chociaż możesz chcieć użyć cmp zamiast diff.

Z innej uwagi, może okazać się pomocne, aby przejść do przodu i wziąć zanurz i użyj automake. Twój Makefile.am (w całości) będzie wyglądać tak:

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

I otrzymasz za darmo mnóstwo naprawdę ładnych celów, w tym całkiem w pełni funkcjonalny framework testowy.

 2
Author: William Pursell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-08 12:53:20