实现`make check`或`make test`

J. *_*mon 23 testing makefile gnu-make regression-testing

如何使用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)
Run Code Online (Sandbox Code Playgroud)

我想要进行一系列的回归测试,例如,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
Run Code Online (Sandbox Code Playgroud)

我想在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]
Run Code Online (Sandbox Code Playgroud)

我的问题:
•我在[东西]占位符中添加了什么?
•有没有办法diff用消息说"测试expr失败" 来替换消息?

Ric*_*ley 16

如问题中所述,您最初的方法是最好的.您的每个测试都以一对预期输入和输出的形式出现.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."
Run Code Online (Sandbox Code Playgroud)

该解决方案直接解决您的原始问题:

  • 你要找的是占位符$<$(word 2, $?)相应的先决条件%.test-in%.test-cmp分别.与@reinierpost注释相反,不需要临时文件.
  • 差异消息被隐藏并使用替换echo.
  • make -k无论单个测试是失败还是成功,都应该调用makefile 来运行所有测试.
  • make -k all 只有在所有测试成功后才会运行.

我们all-tests通过利用文件命名约定(*.test-in)和文件名的GNU make 函数来定义变量时,避免手动枚举每个测试.作为奖励,这意味着解决方案可以扩展到数万个开箱即用的测试,因为GNU make 中变量的长度是无限的.这比基于shell的解决方案更好,一旦达到操作系统命令行限制,该解决方案就会失败.

  • 谢谢,通过提取GNU make手册并完成这个例子,我学到了很多东西! (3认同)

Jac*_*lly 11

制作一个测试运行器脚本,该脚本采用测试名称并推断输入文件名,输出文件名和smaple数据:

#!/bin/sh
set -e
jscheme < $1.in > $1.out 2>&1
diff -q $1.out $1.cmp
Run Code Online (Sandbox Code Playgroud)

然后,在你的Makefile:

TESTS := expr unrecognised

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

您也可以尝试推行类似automake简单测试框架.