Реализация `make check` или` make test` - PullRequest
20 голосов
/ 08 февраля 2011

Как я могу реализовать простой каркас регрессионного теста с помощью Make? (Я использую GNU Make, если это имеет значение.)

Мой текущий make-файл выглядит примерно так (отредактировано для простоты):

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)

Я хотел бы иметь набор регрессионных тестов, например, , expr.in тестирование "хорошего" выражения и unrecognized.in тестирование "плохого" выражения с expr.cmp & unrecognized.cmp быть ожидаемым результатом для каждого. Ручное тестирование будет выглядеть так:

$ 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

Я подумал добавить набор правил в make-файл, который будет выглядеть примерно так:

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]

Мои вопросы:
• Что я помещаю в [что-то] заполнители?
• Есть ли способ заменить сообщение из diff на сообщение «Тест expr не пройден»?

Ответы [ 4 ]

13 голосов
/ 08 января 2015

Ваш оригинальный подход, как указано в вопросе, является лучшим.Каждый из ваших тестов представлен в виде пары ожидаемых входов и выходов.Make вполне способен выполнять итерации и запускать тесты;нет необходимости использовать цикл shell for.Фактически, делая это, вы теряете возможность выполнять свои тесты параллельно и создаете для себя дополнительную работу для очистки временных файлов (которые не нужны).

Вот решение (на примере которого bc ):

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

Решение напрямую обращается к вашим первоначальным вопросам:

  • TheЗаполнители, которые вы ищете, это $< и $(word 2, $?), соответствующие предварительным условиям %.test-in и %.test-cmp соответственно.В отличие от @reinierpost комментарии, временные файлы не нужны.
  • Сообщение diff скрыто и заменяется с помощью echo.
  • . Для запуска всех тестов make-файл должен быть вызван с помощью make -k.независимо от того, будет ли отдельный тест неудачным или успешным.
  • make -k all будет выполняться только в случае успеха всех тестов.

Мы избегаем перечисления каждого теста вручную при определении переменной all-testsиспользуя соглашение об именах файлов (*.test-in) и GNU make функции для имен файлов .В качестве бонуса это означает, что решение масштабируется до десятков тысяч тестов из коробки, так как длина переменных составляет неограничено в GNU make.Это лучше, чем решение на основе оболочки, которое упадет после того, как вы достигнете операционной системы ограничение командной строки .

10 голосов
/ 08 февраля 2011

Создайте сценарий запуска теста, который принимает имя теста и выводит из него имя входного файла, имя выходного файла и smaple данные:

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

Затем в вашем Makefile:

TESTS := expr unrecognised

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

Вы также можете попробовать реализовать что-то вроде automake простой тестовый фреймворк .

3 голосов
/ 11 февраля 2011

То, что я закончил, выглядит так:

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

Он основан на идее Джека Келли, включая наконечник Джонатана Леффлера.

2 голосов
/ 08 февраля 2011

Я отвечу только на ваш вопрос о diff. Вы можете сделать:

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

хотя вы можете использовать cmp вместо diff.

С другой стороны, вам может быть полезно пойти дальше и взять окунитесь и используйте automake. Ваш Makefile.am (полностью) будет выглядеть так:

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

и вы получите множество действительно хороших целей бесплатно, включая довольно полнофункциональный тестовый фреймворк.

...