33

Make を使用して単純な回帰テスト フレームワークを実装するにはどうすればよいですか? (それが問題なら、私はGNU Makeを使用しています。)

私の現在のmakefileは次のようになります(簡単にするために編集されています):

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

次のようなメイクファイルに一連のルールを追加することを考えました。

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]

私の質問:
• [something] プレースホルダーには何を入れますか? • からのメッセージを「テストに失敗しました」という
メッセージに置き換える方法はありますか?diffexpr

4

4 に答える 4

19

質問に記載されているように、元のアプローチが最適です。各テストは、予想される入力と出力のペアの形式になっています。Make は、これらを反復してテストを実行することができます。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."

このソリューションは、元の質問に直接対処します。

  • 探しているプレースホルダーは、前提条件とそれぞれ$<$(word 2, $?)対応しています。@reinierpost コメントとは対照的に、一時ファイルは必要ありません。%.test-in%.test-cmp
  • diff メッセージは非表示になり、 を使用して置き換えられechoます。
  • make -k個々のテストが失敗するか成功するかに関係なく、すべてのテストを実行するには、makefile を呼び出す必要があります。
  • make -k allすべてのテストが成功した場合にのみ実行されます。

all-testsファイル命名規則 ( *.test-in) とファイル名の GNU make関数を活用することにより、変数を定義するときに手動で各テストを列挙することを避けます。おまけとして、 GNU make では変数の長さが無制限であるため、このソリューションはそのままで何万ものテストに拡張できることを意味します。これは、オペレーティング システムのコマンド ラインの制限に達すると失敗するシェル ベースのソリューションよりも優れています。

于 2015-01-08T10:34:39.133 に答える
13

テスト名を取得し、そこから入力ファイル名、出力ファイル名、および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単純なテストフレームワークのようなものを実装してみることもできます。

于 2011-02-08T02:39:46.807 に答える
4

私が最終的に得たものは次のようになります:

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

これはジャック・ケリーのアイデアに基づいており、ジョナサン・レフラーのヒントが含まれています。

于 2011-02-10T22:37:52.580 に答える
2

diff に関するあなたの質問にだけ答えます。できるよ:

diff file1 file2 > /dev/null || echo テストは何とか失敗しました >&2

ただし、diff の代わりに cmp を使用することもできます。

別の注意として、先に進んで思い切ってautomakeを使用すると役立つ場合があります。Makefile.am (全体) は次のようになります。

bin_PROGRAMS = jscheme
jscheme_SOURCES = jscheme.c utility.c model.c read.c eval.c print.c jscheme.h
TESTS = テストスクリプト

そして、かなりフル機能のテスト フレームワークを含む、非常に優れたターゲットを無料で大量に入手できます。

于 2011-02-08T10:54:09.853 に答える