web-dev-qa-db-ja.com

`make check`または` make test`の実装

Makeで単純な回帰テストフレームワークを実装するにはどうすればよいですか? (必要に応じて、GNU 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.cmpunrecognized.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]プレースホルダーには何を入れますか?
diffからのメッセージを「Test expr failed」というメッセージで置き換える方法はありますか?

24
J. C. Salomon

質問で述べられているように、あなたの元のアプローチが最善です。各テストは、予想される入力と出力のペアの形式です。 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."

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

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

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

17
Richard Padley

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

12
Jack Kelly

私が最終的に何をしたかは次のようになります:

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

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

3
J. C. Salomon

Diffについての質問だけを取り上げます。できるよ:

 diff file1 file2>/dev/null ||エコーテスト何とか何とか失敗しました>&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 = test-script 

かなりフル機能のテストフレームワークを含む、本当にたくさんの本当にいいターゲットが無料で手に入ります。

2
William Pursell