1
gcc 4.7.2
c89

你好,

我想知道是否有人知道任何涵盖使用makefile为我的c程序创建一些简单单元测试的教程或教科书。

我想运行一些自动化测试来创建一个测试套件并将其添加到我的 Makefile 中。

只是想要一些关于如何开始的想法。

非常感谢您的任何建议

4

2 回答 2

10

确实是的,不到 30 行的 就可以构建一个通用的单元测试引擎。

请注意,我为测试脚本编写了以下内容,但可以轻松地为定制它。实际上,恕我直言,整个事情都是脚本功能的一个很好的例子。

首先,您将所有测试都是可执行文件放在一些$Testdir. 在这个例子中,所有的测试都有文件名001 002等(没有扩展名)。

接下来,您需要一些设置的东西:

Here=$(PWD)
Testdir=$(Here)/eg
ready:  $(Testdir) $(Tmp)
$(Tmp) :
        @ - [ ! -d $(Tmp) ] && mkdir $(Tmp)

然后您需要将所有测试收集到一个名为的列表中$Tests

Tests:=$(shell cd $(Testdir); ls  | egrep '^[0-9]+$$' | sort -n  )

(注意使用:=. The 是一个轻微的优化,构建$Tests一次,多次使用。)

$(X)我列表中的每个文件$Tests都可以通过两种方式执行。首先,你可以run做到。其次,您可以运行它并将cache结果保存在$(X).want.

run : ready $(Testdir)/$(X)
        @echo $X 2>&1
        @cat $(Testdir)/$(X) | $(Run)  

cache : ready
       @$(MAKE) run | tee $(Testdir)/$X.want
       @echo new test result cached to $(Testdir)/$X.want

cache一旦测试准备好并产生正确的输出,我就会得到一个测试结果。

实际执行由一个名为$(Run). 这是您必须专门为正在测试的语言编写的内容。作为记录,我正在测试 Gawk 脚本,所以我$(Run)的脚本如下(您可以将其更改为您需要的任何内容)。

Run= gawk -f mycode.awk

一旦完成,然后运行一个测试,我只需将运行后得到$(X)的结果与缓存副本进行比较:

test : ready $(Testdir)/$(X).want
      @$(MAKE) run > $(Tmp)/$X.got 
      @if diff -s $(Tmp)/$X.got $(Testdir)/$X.want > /dev/null;  \
        then echo PASSED $X ; \
        else echo FAILED $X,  got $(Tmp)/$X.got; \
        fi

这就是我运行所有测试的方式:

tests:;  @$(foreach x, $(Tests), $(MAKE) X=$x test;)

您还可以对所有当前输出进行批量缓存(警告:除非您的测试当前正在生成正确的输出,否则不要这样做):

cache :
        @$(foreach x, $(Tests), $(MAKE) X=$x cache;)

最后,如果您愿意,您还可以获得 PASSED 和 FAILED 的最终分数:

score :
       @$(MAKE) tests | cut -d\  -f 1 | egrep '(PASSED|FAILED)' | sort | uniq -c 

就是这样:正如所承诺的 - Make 中的通用单元工具,不到 30 行。分享和享受。

于 2012-10-09T02:06:53.140 回答
1

生成测试函数片段

gccxml在和的帮助下生成函数片段很容易nmgenerate_snippets.sh可以使用一个命令行参数调用以下 bash 脚本,为源文件中定义的每个函数生成一个测试函数片段:

#!/bin/bash
#
# Generate stub functions for one file
#

# # Initialize
FILE=$1

[ ! -e "$FILE" ] && echo "file doesn't exist" && exit -1

# # Compile
OBJECT=$(mktemp)
gcc -c $FILE -o $OBJECT

# # Get Functions

# ## Get all symbols in the text sections
Y=$(mktemp)
nm $OBJECT | grep " T " | awk '{print $3;}' | sort > $Y

# ## Get functions defined in the file (including #includes)
# get all functions defined in the compilation unit of $FILE, excluding included
# dynamically linked functions

XML=$(mktemp)
X=$(mktemp)
gccxml $FILE -fxml=$XML
grep "<Function" $XML | sed 's/^.*name="\([^"]*\).*/\1/g' | sort > $X

# ## get the common lines
# This is done to get those functions which are defined in the source file and end up in
# the compiled object file.
COMMON=$(comm $Y $X -1 -2)

# # Create stubs
for func in $COMMON;
do
    cat <<_
// Test stub for $func. Returns 1 if it fails.
char test_$func() {
    return 1;
}
_

done

# # Clean up

rm $OBJECT $XML $X $Y

待办事项

剧本还不完善。您可能应该包含一个测试,只为那些尚未测试的函数生成测试函数。由于这类似于查找$X和之间的常用名称$Y,因此我将其留作练习。实现这一点后,从 Makefile 运行此脚本是有意义的。请参阅其他答案以获取有关指示。

示例用法

考虑 C 文件hello.c

#include <stdio.h>

int foo();
int bar();

int main() {
    printf("hello, world\n");
    return 0;
}


int foo() {
    printf("nothing\n");
    return 1;
}

int bar() {
    printf("still nothing\n");
    return 1;
}

将此文件作为输入运行上面的脚本会产生以下输出:

// Test stub for bar. Returns 1 if it fails.
char test_bar() {
    return 1;
}
// Test stub for foo. Returns 1 if it fails.
char test_foo() {
    return 1;
}
// Test stub for main. Returns 1 if it fails.
char test_main() {
    return 1;
}

只需将这些片段放入适当的文件中,并根据需要用逻辑填充它们。之后,编译测试套件并运行它。

于 2012-10-09T14:18:09.517 回答