不使用Autotools如何使用C单元测试框架Check?

28

我想跟随官方Check教程学习,但需要具备Autotools的工作知识,而我并没有。我希望只是写几个快速测试,但我发现这个教程很无从下手。它依赖于Autoconf、Automake和一些Check宏中的许多魔法。它没有解释Check实际上是如何工作的,以便我可以手动构建测试。

我如何在没有Autotools的情况下使用Check?


我编辑了这个问题,我认为现在可以重新打开它,但我不清楚如何操作。 - Merlijn Sebrechts
1
@MerlijnSebrechts 需要足够的声望值(或者是原始发布者)才能进行操作。我同意,所以现在投票重新开放。 - hyde
1
感谢 @MerlijnSebrechts 进行清理。我也投票支持重新开放。 - Mark E. Haase
非常感谢您的提问,@Mark E. Haase。我同意您的观点,Check的教程确实让人感到不知所措。我尝试下载freestyler答案的dropbox链接,但没有成功。由于您在2013年提出了这个问题,您可能已经找到了解决方案并将check集成到了您的工作流程中。您知道在哪里可以找到一个使用check进行单元测试的简单示例吗? - ecjb
2个回答

49
你肯定不需要学习 autotools 就可以在小型项目中使用 Check。 假设我们的 main() 在 main.c 中,而我们的 implementation.c 中有一个函数用于求两个整数的和。 (implementation.h 只包含函数原型)
#include "implementation.h"

int sum(int a, int b) {

    return a + b;
}

你可以这样编写一个测试:
#include "implementation.h"

#test sum2test
    fail_unless(sum(3, 2) == 5, "sum function borked");
    fail_unless(sum(-3, 2) == -1, "sum function borked");
    fail_unless(sum(3, -2) == 1, "sum function borked");
    fail_unless(sum(-3, -2) == -5, "sum function borked");

将文件保存为implementation-test.check(您可以选择任何名称/扩展名,但如果要遵循我的指南,请保持这些名称),然后运行附带Check的awk脚本。 您甚至不必费心编写检查框架的样板代码!(有关更多详细信息,请参见man checkmk)

checkmk implementation-test.check >implementation-test.c

输出将如下所示:
/*
 * DO NOT EDIT THIS FILE. Generated by checkmk.
 * Edit the original source file "implementation-test.check" instead.
 */

#include <check.h>

#line 1 "implementation-test.check"
#include "implementation.h"

START_TEST(sum2test)
{
#line 4
    fail_unless(sum(3, 2) == 5, "sum function borked");
    fail_unless(sum(-3, 2) == -1, "sum function borked");
    fail_unless(sum(3, -2) == 1, "sum function borked");
    fail_unless(sum(-3, -2) == -5, "sum function borked");
}
END_TEST

int main(void)
{
    Suite *s1 = suite_create("Core");
    TCase *tc1_1 = tcase_create("Core");
    SRunner *sr = srunner_create(s1);
    int nf;

    suite_add_tcase(s1, tc1_1);
    tcase_add_test(tc1_1, sum2test);

    srunner_run_all(sr, CK_ENV);
    nf = srunner_ntests_failed(sr);
    srunner_free(sr);

    return nf == 0 ? 0 : 1;
}

然后只需要在编译时加入-lcheck,就可以将检查库链接并运行程序!
gcc -Wall -o sum2ints-test implementation.c implementation-test.c -lcheck
./sum2ints

以下是一个简单的Makefile让你开始。将它保存在sum2ints.makefile中,然后运行以下命令以构建implementation.c和main:
```make -f sum2ints.makefile```
make -f sum2ints.makefile

要使用从checkmk创建的implementation-test.c与我们的实现文件implementation.c进行构建和运行,请执行以下操作:
make -f sum2ints.makefile test

-

CFLAGS=-Wall
LIBS=-lcheck

all: sum2ints

sum2ints: main.o implementation.o
gcc -o sum2ints main.o implementation.o

main.o: main.c implementation.h
gcc $(CFLAGS) -c main.c

implementation.o: implementation.c implementation.h
gcc $(CFLAGS) -c implementation.c

test: sum2ints-test
./sum2ints-test

sum2ints-test: implementation-test.o implementation.o
gcc -o sum2ints-test implementation.o implementation-test.o $(LIBS)

implementation-test.o: implementation-test.c implementation.h
gcc $(CFLAGS) -c implementation-test.c

我已为您准备了一个.zip文件,其中包含上述所有内容。

https://dl.dropbox.com/u/1987095/test-check.zip


3
在Debian“Jessie”上,我需要链接额外的库:LIBS=-lcheck -lm -lpthread -lrt - Mateusz Charytoniuk
谢谢!起初我学习使用autotools进行检查,但对于小项目而言,你的教程非常好! - Grigory
1
checkmk 看起来很酷,但它并不一定与 check 捆绑在一起,它是一个独立的项目 - rampion
使用“GNU Make 3.81”和“gcc(Ubuntu 4.8.4-2ubuntu1〜14.04.1)4.8.4”,如果我不添加-pthread和-lm参数,就会出现对floor,__pthread_register_cancel,timer_create,timer_settime和timer_delete的未定义引用。@freestyler - JeffH
4
针对在Ubuntu中出现问题的JeffH及其他用户,您可以通过运行pkg-config --cflags --libs check来确定需要添加的附加内容,该命令可能会返回以下内容:-pthread -pthread -lcheck_pic -lrt -lm。请使用此整个字符串代替原作者提供的-lcheck - skelliam
非常感谢您的回答@freestyler。我同意Mark E. Haase的观点,即Check的教程令人不知所措。我尝试下载您的Dropbox链接,但出现错误消息。是否可能创建新链接或将所需文件复制到问题中,并输出主目录的树形结构? - ecjb

13

@freestyler的答案很好,但仍然使用checkmk,这是不必要的。

这是一个最小化的示例,不使用checkmk

将以下内容放入名为test.c的文件中:

#include <check.h>

START_TEST (sanity_check)
{
    fail_unless(5 == 5, "this should succeed");
    fail_unless(6 == 5, "this should fail");
}
END_TEST

int main(void)
{
    Suite *s1 = suite_create("Core");
    TCase *tc1_1 = tcase_create("Core");
    SRunner *sr = srunner_create(s1);
    int nf;

    suite_add_tcase(s1, tc1_1);
    tcase_add_test(tc1_1, sanity_check);

    srunner_run_all(sr, CK_ENV);
    nf = srunner_ntests_failed(sr);
    srunner_free(sr);

    return nf == 0 ? 0 : 1;
}

并编译使用

gcc test.c -Wall -o test -lcheck -pthread -lcheck_pic -pthread -lrt -lm -lsubunit

太棒了。我不明白为什么文档中没有提供一个最简单的示例。无论如何,我让它工作了,但在编译使用一些你使用的选项时出现了一些错误(我是一个完全的C初学者,所以不确定其中一些选项是什么)。无论如何,对我来说,它可以用以下方式工作:gcc test.c -Wall -o test -lcheck -pthread -pthread -lm - Aaron
非常感谢@MerlijnSebrechts。正如Aaron和Mark E. Haase所说,我也发现check的教程非常令人不知所措。在安装了check之后,我运行了您的命令,但在MacOS 11.6.1上收到了以下错误消息:ld: library not found for -lcheck_pic clang: error: linker command failed with exit code 1 (use -v to see invocation)。您知道可能出了什么问题吗? - ecjb
我刚刚在这里发布了一个关于此事的问题:https://dev59.com/eNL7oIgBc1ULPQZFuvZo - ecjb
我刚刚在这里发布了一个关于这个问题的提问:https://stackoverflow.com/questions/75296574/unit-test-with-check-library-on-macos-11-6-1-ld-library-not-found-for-lcheck - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接