Writing and Running Unit Tests in Autotools

Introduction

If your project is like others, you’ll probably have a util.h and util.c files containing general utility functions. For example, suppose you want a function strnspn that’s like strspn() except limits the number of characters c…


This content originally appeared on DEV Community and was authored by Paul J. Lucas

Introduction

If your project is like others, you’ll probably have a util.h and util.c files containing general utility functions. For example, suppose you want a function strnspn that’s like strspn() except limits the number of characters checked to n:

size_t strnspn( char const *s, char const *charset, size_t n );

For such fundamental functions, you want to ensure they work correctly in all cases, including degenerate cases, so that if your program has a bug, you can reasonably rule out the bug being in one of those functions. To do that, you need to write unit tests for them.

A Simple Unit Unit Test Framework

In order to write unit tests, a small framework is helpful. Yes, I’m aware of this:

Standards

Specifically, there are several open-source, unit-test frameworks for C and they’re probably good; but I wanted something extremely simple. To that end, here’s unit_test.h:

// unit_test.h

#define TEST(EXPR)  ( !!(EXPR) || TEST_FAILED( #EXPR ) )

#define TEST_FAILED(EXPR) \
  ( fprintf( stderr, "%s:%d: " EXPR "\n", prog_name, __LINE__ ), \
    !++test_failures )

#define TEST_FUNC_BEGIN() \
  unsigned const test_failures_start = test_failures

#define TEST_FUNC_END() \
  return test_failures == test_failures_start

To write unit tests, write one function for each “thing” you want to test where “thing” can be a single function or a few related functions:

static bool test_whatever( void ) {
  TEST_FUNC_BEGIN();

  TEST( whatever( ... ) ) == 42 );

  TEST_FUNC_END();
}

If a test fails, the TEST macro will print the stringified expression that didn’t evaluate to true and its line number.

Note that the TEST macro also returns the success of the test so it can be used in a condition since there are some tests that depend on the success of earlier tests. For example, if you’re testing linked-list functions and you expect the front of the list to be the value “A,” you first want to test that the result isn’t NULL:

char const *const result = slist_front( list );
if ( TEST( result != NULL ) )
  TEST( strcmp( result, "A" ) == 0 );

Similarly, a test function returns the success of the entire set of tests within the function in case other test functions depend on the success of earlier functions.

To write tests for strnspn, you’d create a file like:

// util_test.c

// local
#include "config.h"
#include "util.h"
#include "unit_test.h"

// standard
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

char const *prog_name;
unsigned test_failures;

static bool test_strnspn( void ) {
  TEST_FUNC_BEGIN();

  TEST( strnspn( "", "AB", 0 ) == 0 );

  TEST( strnspn( "A",   "AB", 0 ) == 0 );
  TEST( strnspn( "B",   "AB", 0 ) == 0 );
  TEST( strnspn( "X",   "AB", 0 ) == 0 );

  TEST( strnspn( "XA",  "AB", 0 ) == 0 );
  TEST( strnspn( "XB",  "AB", 0 ) == 0 );
  TEST( strnspn( "XAB", "AB", 0 ) == 0 );

  TEST( strnspn( "A",   "AB", 1 ) == 1 );
  TEST( strnspn( "B",   "AB", 1 ) == 1 );

  TEST( strnspn( "AB",  "AB", 2 ) == 2 );
  TEST( strnspn( "BA",  "AB", 2 ) == 2 );

  TEST( strnspn( "ABA", "AB", 2 ) == 2 );
  TEST( strnspn( "ABX", "AB", 2 ) == 2 );

  TEST_FUNC_END();
}

int main( int argc, char const *const argv[] ) {
  prog_name = argv[0];
  test_strnspn();
  printf( "%u failures\n", test_failures );
  exit( test_failures > 0 );
}

Integrating with Autoconf

To have Autoconf compile your test programs, add the following to src/Makefile.am:

check_PROGRAMS =    util_test

util_test_SOURCES = config.h unit_test.h util_test.c

Then if you type make check, your test programs will be compiled at which point you can run them manually. To have make check also run the test programs automatically, also add the following to src/Makefile.am:

TESTS =             $(check_PROGRAMS)

Conclusion

Any non-trivial project should include unit tests for all fundamental functions that can be tested independently using stand-alone executables. A simple testing framework helps write tests. Unit tests can be integrated with Autoconf to compile and run them.

There are more parts to come!


This content originally appeared on DEV Community and was authored by Paul J. Lucas


Print Share Comment Cite Upload Translate Updates
APA

Paul J. Lucas | Sciencx (2025-10-24T12:43:57+00:00) Writing and Running Unit Tests in Autotools. Retrieved from https://www.scien.cx/2025/10/24/writing-and-running-unit-tests-in-autotools/

MLA
" » Writing and Running Unit Tests in Autotools." Paul J. Lucas | Sciencx - Friday October 24, 2025, https://www.scien.cx/2025/10/24/writing-and-running-unit-tests-in-autotools/
HARVARD
Paul J. Lucas | Sciencx Friday October 24, 2025 » Writing and Running Unit Tests in Autotools., viewed ,<https://www.scien.cx/2025/10/24/writing-and-running-unit-tests-in-autotools/>
VANCOUVER
Paul J. Lucas | Sciencx - » Writing and Running Unit Tests in Autotools. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/10/24/writing-and-running-unit-tests-in-autotools/
CHICAGO
" » Writing and Running Unit Tests in Autotools." Paul J. Lucas | Sciencx - Accessed . https://www.scien.cx/2025/10/24/writing-and-running-unit-tests-in-autotools/
IEEE
" » Writing and Running Unit Tests in Autotools." Paul J. Lucas | Sciencx [Online]. Available: https://www.scien.cx/2025/10/24/writing-and-running-unit-tests-in-autotools/. [Accessed: ]
rf:citation
» Writing and Running Unit Tests in Autotools | Paul J. Lucas | Sciencx | https://www.scien.cx/2025/10/24/writing-and-running-unit-tests-in-autotools/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.