2011-02-07 25 views
16

Makeで単純回帰テストフレームワークを実装するにはどうしたらいいですか? 、私は回帰テストのセットを持っているしたいと思います`make check`や` make test`の実装

OBJS = jscheme.o utility.o model.o read.o eval.o print.o 

%.o : %.c jscheme.h 
    gcc -c -o [email protected] $< 

jscheme : $(OBJS) 
    gcc -o [email protected] $(OBJS) 

.PHONY : clean 

clean : 
    -rm -f jscheme $(OBJS) 

:(。それが重要ならば、私は、GNU Makeを使用しています)

私の現在のメイクファイルは、この(簡単にするために編集した)のようになります例えば,expr.in & unrecognized.in「悪い」をテストし、expr.cmp & unrecognized.cmpがそれぞれの期待される出力であることをテストします。手動テストは、次のようになります。

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] 

私の質問:

$ 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 

私はこのような何か探してメイクファイルにルールのセットを追加すると考えられ、私は入れないどんな•
を[何か]プレースホルダ?
diffのメッセージを "Test expr failed"というメッセージで置き換える方法はありますか?

+0

いつすべての一時ファイルがありますか? – reinierpost

+0

@reinierpostの何が悪いですか:あなたがこれらの比較を行うより良い方法を持っているなら、是非、それを含む回答を投稿してください。それは、私が求めているヘルプの種類です。 –

+0

申し訳ありませんが、私はその質問をキャンセルしたと思いました。あなたは一時ファイルが必要です。 – reinierpost

答えて

8

質問に記載されている元のアプローチが最適です。それぞれのテストは、予想される入力と出力のペアの形をしています。 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 [email protected] failed" && exit 1) 

all : test 
    @echo "Success, all tests passed." 

ソリューションは、直接、元の質問に対処します。あなたが探している

  • プレースホルダは$<に対応する$(word 2, $?)です前提条件%.test-inおよび%.test-cmp。 @reinierpostコメントとは異なり、一時ファイルは必要ありません。
  • 差分メッセージは非表示になり、echoを使用して置き換えられます。
  • 個々のテストが失敗したかどうかに関係なく、すべてのテストを実行するには、makefileをmake -kで起動する必要があります。
  • make -k allは、すべてのテストが成功した場合にのみ実行されます。私たちは、all-tests変数を定義するときに、ファイルの命名規則(*.test-in)とGNUを活用することで、手動で各テストを列挙避ける

functions for file namesを作ります。これは、GNU makeで変数の長さがunlimitedであるため、ソリューションが箱からすぐに数万のテストにスケールアップすることを意味します。これは、オペレーティングシステムcommand line limitにヒットしたら落ちるシェルベースのソリューションより優れています。

+0

関連するGNU Makeマニュアルへのリンクを(https://www.gnu)に含めることができますか? .org/software/make/manual/html_node/File-Name-Functions.html)>? –

+0

喜んで - 完了! –

+1

ありがとう、私は、GNU makeマニュアルを抜き出して、この例を使っていくつかのことを学びました! – dpritch

9

テスト名を取り、入力ファイル名、出力ファイル名とそのからsmapleデータを推測テストランナーのスクリプト作成します:あなたのMakefileで、その後

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

を:

TESTS := expr unrecognised 

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

あなたは可能性がありautomakesimple test frameworkのようなものを実装してみてください。

+1

私は別の目標の私の元の計画以上のシェルループのアイデアが好きです。シェルスクリプトは悪い考えではありませんが、私はすべてをmakefileに組み込むと思います。 –

+1

また、私は、autotools全体の虫の缶を開こうとしていない_really_です。 –

+1

@jcsalomon:私はautotoolsの使用を意味するのではなく、テストシステムがどのように動作するかを調べます。私はあなたの心が変わった場合に備えてここに残します:http://www.lrde.epita.fr/~adl/autotools.html。あなたの 'Makefile'で' $ '記号をエスケープすることを忘れないでください。それは私に数回惹かれました。 –

2

diffについてのご質問のみお答えします。次のようにすることができます:

 
diff file1 file2 > /dev/null || echo Test blah blah failed >&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 

、あなたはかなりフル機能のテストフレームワークを含め、無料で本当にいいのターゲットの全体の多くを取得します。私はこのようなルックスになってしまった何

+0

私はそのシェル機能について忘れてしまいました。ありがとう! –

2

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 

ジョナサン・レフラーの先端が含まれてそれは、ジャック・ケリーの考えに基づいています。

+0

あなたは '||そこのどこかの出口1 '。それ以外の場合は、すべてのテストの失敗を無視しているだけです。 – l0b0

+0

@ 10b0、私は最初の失敗の後に救済したくない。あなたに何かを教えてください。テストのいずれかが失敗した場合でも、すべてのテストが実行された後に、クリーンな方法で「exit 1」を思いつき、私が受けた答えを変更します。 –

+0

'for ...;テストを実行する||エラー= 1;完了しました。 exit $ error'? – l0b0