2011-02-07 154 views
16

如何使用Make實現簡單的迴歸測試框架? (我使用了GNU make,如果該事項。)執行`make check`或`make test`

我現在的makefile文件看起來像這樣(編輯爲簡單起見):

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) 

我想有一套迴歸測試,例如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 

我認爲一組規則添加到Makefile看起來像這樣:

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失敗」?

+0

從哪裏來的所有臨時文件? – reinierpost 2011-02-08 08:47:08

+0

@reinierpost有什麼問題:如果你有更好的方式來進行這些比較,通過一切手段發佈一個包含它們的答案 - 這正是我所要求的那種幫助。 – 2011-02-08 15:01:55

+0

對不起,我以爲我取消了這個問題。你確實需要臨時文件。 – reinierpost 2011-02-08 15:26:14

回答

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替換。
  • 使用make -k調用makefile即可運行所有測試,無論單個測試是失敗還是成功。
  • make -k all只有在所有測試成功時纔會運行。

通過利用文件命名約定(*.test-in)定義all-tests變量時,我們避免手動列舉每個測試和GNU使functions for file names。作爲獎勵,這意味着解決方案可擴展到數萬個開箱即用的測試,因爲GNU make中的變量長度爲unlimited。這比基於shell的解決方案要好,一旦你碰到操作系統command line limit就會崩潰。

9

做一個測試運行腳本,需要一個測試名稱並推斷輸入文件名,輸出文件名和smaple數據來自:

#!/bin/bash 
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 

你可以也嘗試實施類似automakesimple test framework

+1

我喜歡我最初的獨立目標計劃的外殼循環思路。 shell腳本並不是一個壞主意,但我想我會將整個事物合併到makefile中。 – 2011-02-08 15:08:17

+1

另外我真的不想打開整個autotools蠕蟲的罐頭。 – 2011-02-08 15:09:37

2

我會解決你的問題差異。你可以這樣做:

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

雖然你可能想使用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

我最終什麼了這個樣子的:

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 

它是基於傑克凱利的想法,與包括喬納森·萊弗勒的小費。