28

I am trying to follow along with the official Check tutorial, but it requires a working knowledge of Autotools, which I don't have. I was hoping just to write a couple quick tests, and I'm finding this tutorial overwhelming. It relies on a lot of magic in Autoconf, Automake, and some Check macros. It doesn't explain how Check actually works so that I could build tests by hand.

How can I use Check without Autotools?

Merlijn Sebrechts
  • 545
  • 1
  • 5
  • 16
Mark E. Haase
  • 25,965
  • 11
  • 66
  • 72
  • I edited the question, I think it can be reopened now but it's not clear to me how to do that. – Merlijn Sebrechts Aug 25 '20 at 20:17
  • 1
    @MerlijnSebrechts It requires enough reputation (or being the original poster). I agree, so voted to reopen now. – hyde Aug 26 '20 at 04:09
  • 1
    Thanks for the cleanup @MerlijnSebrechts. I've also voted to reopen. – Mark E. Haase Aug 26 '20 at 18:19
  • Many thanks for your question @Mark E. Haase. I agree with youn that the tutorial of Check is overwhelming. I tried to download the dropbox link of the answer of freestyler without success. Since you asked the question in 2013, you might have found a solution and integrated check in your workflow. Do you know where i could find a simple example of unit test with check? – ecjb Jan 31 '23 at 11:18

2 Answers2

49

You certainly don't need to learn autotools to use Check in small projects. Let's say our main() is in main.c and our implementation.c have a function that sums 2 ints. (implementation.h contains just the function prototype)

#include "implementation.h"

int sum(int a, int b) {

    return a + b;
}

You can write a test like so:

#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");

Save the file in implementation-test.check (you can pick any name / extension you want, but stay with those if you want to follow my guide) and then run the included awk script that comes with Check. You don't even have to bother with the boilerplate code for the check framework! (for more details man checkmk)

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

The output will be the following:

/*
 * 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;
}

Then just include -lcheck when you compile to get the check library linked in and run the program!

gcc -Wall -o sum2ints-test implementation.c implementation-test.c -lcheck
./sum2ints

Below is a simple makefile to get you started. Save it in sum2ints.makefile and then to build the implementation.c along with main, run:

make -f sum2ints.makefile

To build & run the implementation.c with our implementation-test.c that got created from checkmk, run:

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

I've prepared a .zip file for you containing all the above.

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

freestyler
  • 606
  • 7
  • 6
  • 2
    On Debian "Jessie" I needed to link additional libraries: `LIBS=-lcheck -lm -lpthread -lrt` – Mateusz Charytoniuk Dec 25 '13 at 17:27
  • Thank you! At first I've learnt how to use check with autotools but for smaller projects your tutorial rocks! – Grigory Jan 17 '15 at 08:31
  • 1
    `checkmk` looks cool, but it's not necessarily bundled with `check`, [it's a separate project](http://micah.cowan.name/projects/checkmk/). – rampion Jan 18 '15 at 02:40
  • Using "GNU Make 3.81" and "gcc (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4", I get undefined references to floor, __pthread_register_cancel, timer_create, timer_settime, and timer_delete unless I add the -pthread and -lm arguments. @freestyler – JeffH Jun 26 '16 at 17:32
  • 4
    @JeffH, for you and others having issues in Ubuntu, you can figure out what additionally you need to add with `pkg-config --cflags --libs check`, which will probably return something like `-pthread -pthread -lcheck_pic -lrt -lm` Use this entire string in place of the author's `-lcheck`. – skelliam Oct 19 '16 at 01:21
  • Many thanks for your answer @freestyler. I agree with Mark E. Haase in that the tutorial of Check is overwhelming. I tried to download your dropbox link but I get an error message. Would it be possible to make new link or copy the needed files in the question with a tree output of the main directory? – ecjb Jan 31 '23 at 11:16
12

The answer of @freestyler is good, but it still uses checkmk, which is not necessary.

This is a minimal example without using checkmk.

Put the following in a file named 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;
}

and compile with

gcc test.c -Wall -o test -lcheck -pthread -lcheck_pic -pthread -lrt -lm -lsubunit
Merlijn Sebrechts
  • 545
  • 1
  • 5
  • 16
  • This is great. I don't understand why in the docs they don't provide a simplest case example. In any case, I got this working but got some errors compiling with some of the options you used (I am a total C beginner, so not sure what some of these options are). Regardless, for me it works with: gcc test.c -Wall -o test -lcheck -pthread -pthread -lm – Aaron Mar 29 '22 at 05:25
  • Many thanks @MerlijnSebrechts. As said by Aaron and Mark E. Haase, I also found the tutorial of check completely overwhelming. After having installed check, I run your command but got the following error message on 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)`. Do you know what could have gone wrong? – ecjb Jan 31 '23 at 11:24
  • I just posted a question regarding this there: https://stackoverflow.com/questions/75296574/unit-test-with-check-library-on-macos-11-6-1-ld-library-not-found-for-lcheck – ecjb Jan 31 '23 at 11:40