Skip to content

vpiotr/utest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Overview

Build Status License C++11

Micro (header-only) library for unit testing.

Library author: Piotr Likus

Created: 31/08/2020

Initial code based on blog post by Bastian Rieck, see: https://bastian.rieck.me/blog/posts/2017/simple_unit_tests/

Requirements

This library requires C++11 or later and has been tested on Linux Mint 20 and other modern Linux distributions.

Key C++11 features used:

  • Lambda expressions
  • auto keyword for type deduction
  • Uniform initialization syntax ({})
  • std::enable_if for SFINAE
  • std::chrono for timing
  • nullptr and std::nullptr_t
  • static_assert for compile-time checks
  • decltype for type deduction

The library is fully compatible with C++11, C++14, C++17, and C++20 standards.

Project home

https://github.com/vpiotr/utest

Build and Installation

Building the demo and tests

mkdir _build && cd _build
cmake ..
cmake --build .

# Run the demo
./bin/utest_demo

# Run the tests
ctest
# or
make test

Installing the library

mkdir _build && cd _build
cmake ..
cmake --build .
sudo cmake --install .

Helper Scripts

The project includes several helper scripts for common tasks:

  • rebuild.sh - Clean and rebuild the entire project from scratch
  • run_demos.sh - Execute all demo programs sequentially with detailed output and summary
  • run_tests.sh - Run all test executables with summary reporting (use --detailed for full output)
  • build_docs.sh - Generate Doxygen documentation in HTML format

Usage examples:

# Quick rebuild
./rebuild.sh

# Run all demos with colored output
./run_demos.sh

# Run tests with summary only
./run_tests.sh

# Run tests with detailed output
./run_tests.sh --detailed

# Generate documentation
./build_docs.sh

CMake Options

  • UTEST_BUILD_DEMO: Build the demo project (ON by default)
  • UTEST_BUILD_TESTS: Build the tests (ON by default)

Example with options:

cmake -DUTEST_BUILD_DEMO=OFF -DUTEST_BUILD_TESTS=ON ..

Integration

C++11 Compatibility

This library is fully compatible with C++11 and later standards. To use it in your project, ensure your compiler supports C++11:

# In your CMakeLists.txt
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

Or with compiler flags:

g++ -std=c++11 your_tests.cpp
clang++ -std=c++11 your_tests.cpp

The library leverages modern C++11 features for clean, expressive test code while maintaining compatibility with older codebases.

Method 1: Direct inclusion

Simply copy include/utest.h into your project and include it.

Method 2: CMake integration

Add utest as a subdirectory in your CMake project:

add_subdirectory(path/to/utest)
target_link_libraries(your_project PRIVATE utest)

Or, if installed:

find_package(utest REQUIRED)
target_link_libraries(your_project PRIVATE utest::utest)

How to use library

This library is header-only solution, so you just need to include single header file utest.h in your test runner code.

Create a runner application executing single function which executes all tests plus adds prolog (UTEST_PROLOG) and epilog (UTEST_EPILOG) code. Each test must be prepared as a function called test_aaa and must be registered using UTEST_FUNC macro.

Example complete test runner:

#include "utest.h"

void test_assert_equals() {
    int a{42};
    UTEST_ASSERT_EQUALS(a, 42);
}

int run_all_tests() {
    UTEST_PROLOG();
    UTEST_FUNC(assert_equals);
    UTEST_EPILOG();
}

int main() {
    return run_all_tests();
}

See tests in "tests" subdirectory and the "demo" directory for more examples.

Demo Project

The demo project demonstrates various aspects of the library across multiple executable demos:

Available Demos

1. Core Features Demo (utest_demo)

  • File: demo_core_features.cpp
  • Executable: ./bin/utest_demo
  • Features demonstrated:
    • Basic assertions (equality, true/false)
    • Assertions with custom error messages
    • Exception testing with lambda functions
    • Complex test scenarios with collections and vectors
    • String comparisons and container operations

2. Unicode Checkmarks Demo (demo_unicode_checkmarks)

  • File: demo_unicode_checkmarks.cpp
  • Executable: ./bin/demo_unicode_checkmarks
  • Features demonstrated:
    • Default Unicode checkmark output format
    • Test grouping with UTEST_FUNC_DEF2 syntax
    • Multiple grouped test scenarios
    • Various assertion types (GT, GTE, NEQ, etc.)

3. Verbose Mode Demo (demo_verbose_mode)

  • File: demo_verbose_mode.cpp
  • Executable: ./bin/demo_verbose_mode
  • Features demonstrated:
    • Verbose output mode showing test names before execution
    • Performance timing measurements
    • Grouped test organization and display
    • Test progress tracking

4. Failure Handling Demo (demo_with_failure)

  • File: demo_with_failure.cpp
  • Executable: ./bin/demo_with_failure
  • Features demonstrated:
    • Intentional test failures for error reporting demonstration
    • Comprehensive error messages with file/line information
    • Mixed passing and failing tests in the same runner
    • Error handling and exit code behavior

5. No Tests Scenario Demo (demo_no_tests)

  • File: demo_no_tests.cpp
  • Executable: ./bin/demo_no_tests
  • Features demonstrated:
    • Behavior when no tests are registered or executed
    • Default failure handling for empty test suites
    • Use of UTEST_ALLOW_EMPTY_TESTS() for conditional testing

To run all demos:

mkdir _build && cd _build
cmake ..
cmake --build .
./run_demos.sh

To run individual demos:

./bin/utest_demo                # Core features demo
./bin/demo_unicode_checkmarks   # Unicode checkmarks demo  
./bin/demo_verbose_mode         # Verbose mode demo
./bin/demo_with_failure         # Failure handling demo
./bin/demo_no_tests             # No tests scenario demo

Test Output

There are two ways of viewing test results:

  1. As standard application - from IDE or console, this will show which tests are failing, example:
OK: Test [assert_true] succeeded
OK: Test [assert_false] succeeded
OK: Test [assert_true_msg] succeeded
OK: Test [assert_false_msg] succeeded
Error: Test [assert_equals] failed!, error: Assertion failed,  at /home/piotr/tmp/utest/tests/testUTest.cpp:33 in void test_assert_equals(): 42 != 43
OK: Test [assert_equals_msg] succeeded
OK: Test [assert_throws] succeeded
OK: Test [assert_throws_msg] succeeded
Failures!
  1. As make test or ctest - this will only show which runners are failing
piotr@piotr-Prec-M47:~/tmp/utest/_build$ make test
Running tests...
Test project /home/piotr/tmp/utest/_build
    Start 1: testUTest,
1/1 Test #1: testUTest, .......................***Failed    0.00 sec

0% tests passed, 1 tests failed out of 1

Total Test time (real) =   0.00 sec

The following tests FAILED:
      1 - testUTest, (Failed)
Errors while running CTest
make: *** [Makefile:84: test] Error 8

Available macros

Core Macros

  • UTEST_PROLOG() - Initialize the test framework
  • UTEST_EPILOG() - Finalize and report test results
  • UTEST_FUNC(name) - Run a test function (function should be named test_name)
  • UTEST_FUNC2(group, name) - Run a grouped test function (function should be named test_group_name)

Configuration Macros

  • UTEST_ALLOW_EMPTY_TESTS() - Allow test runner to succeed even when no tests are run
  • UTEST_USE_ASCII_CHECKMARKS() - Use ASCII [OK]/[FAIL] instead of Unicode checkmarks
  • UTEST_SHOW_PERFORMANCE() - Enable performance timing for each test
  • UTEST_ENABLE_VERBOSE_MODE() - Show test names before execution (useful for debugging)

Function Definition Macros

  • UTEST_FUNC_DEF(name) - Define a test function: void test_name()
  • UTEST_FUNC_DEF2(group, name) - Define a grouped test function: void test_group_name()

Assertion Macros

  • UTEST_ASSERT_TRUE(condition) - Assert that condition is true
  • UTEST_ASSERT_TRUE_MSG(condition, msg) - Assert that condition is true, with custom message
  • UTEST_ASSERT_FALSE(condition) - Assert that condition is false
  • UTEST_ASSERT_FALSE_MSG(condition, msg) - Assert that condition is false, with custom message
  • UTEST_ASSERT_EQUALS(a, b) - Assert that a equals b
  • UTEST_ASSERT_EQUALS_MSG(a, b, msg) - Assert that a equals b, with custom message
  • UTEST_ASSERT_NOT_EQUALS(a, b) - Assert that a does not equal b
  • UTEST_ASSERT_NOT_EQUALS_MSG(a, b, msg) - Assert that a does not equal b, with custom message
  • UTEST_ASSERT_STR_EQUALS(a, b) - Assert that strings a and b are equal
  • UTEST_ASSERT_STR_NOT_EQUALS(a, b) - Assert that strings a and b are not equal
  • UTEST_ASSERT_GT(a, b) - Assert that a is greater than b
  • UTEST_ASSERT_GTE(a, b) - Assert that a is greater than or equal to b
  • UTEST_ASSERT_LT(a, b) - Assert that a is less than b
  • UTEST_ASSERT_LTE(a, b) - Assert that a is less than or equal to b
  • UTEST_ASSERT_THROWS(F) - Assert that function F throws an exception
  • UTEST_ASSERT_THROWS_MSG(F, MSG) - Assert that function F throws an exception, with custom message
  • UTEST_ASSERT_DOES_NOT_THROW(F) - Assert that function F does not throw an exception
  • UTEST_ASSERT_DOES_NOT_THROW_MSG(F, MSG) - Assert that function F does not throw an exception, with custom message
  • UTEST_ASSERT_NULL(ptr) - Assert that pointer ptr is null
  • UTEST_ASSERT_NOT_NULL(ptr) - Assert that pointer ptr is not null

Convenient Aliases

  • UTEST_ASSERT_EQ(a, b) - Alias for UTEST_ASSERT_EQUALS
  • UTEST_ASSERT_NEQ(a, b) - Alias for UTEST_ASSERT_NOT_EQUALS
  • UTEST_ASSERT_SEQ(a, b) - Alias for UTEST_ASSERT_STR_EQUALS
  • UTEST_ASSERT_SNEQ(a, b) - Alias for UTEST_ASSERT_STR_NOT_EQUALS

Build Organization

The build system organizes binaries into dedicated subdirectories:

  • Main demo: bin/utest_demo
  • Additional demos: bin/demo_unicode_checkmarks, bin/demo_verbose_mode, bin/demo_with_failure, bin/demo_no_tests
  • Tests: bin/tests/test_*

Handling No Tests Scenario

By default, if no tests are run, the test framework will exit with failure. This can be changed using:

UTEST_PROLOG();
UTEST_ALLOW_EMPTY_TESTS(); // Allow success even with no tests
// No test functions called here
UTEST_EPILOG(); // Will return SUCCESS instead of FAILURE

This is useful for:

  • Conditional test execution
  • Test suites that may be empty under certain conditions
  • Template-based test generation where some configurations may produce no tests

New Features

Test Grouping

Tests can be organized into groups using UTEST_FUNC_DEF2 and UTEST_FUNC2:

// Define grouped test functions
UTEST_FUNC_DEF2(ModuleA, Feature1) {
    UTEST_ASSERT_TRUE(some_condition);
}

UTEST_FUNC_DEF2(ModuleA, Feature2) {
    UTEST_ASSERT_EQUALS(calculate(), expected);
}

// Run grouped tests
UTEST_FUNC2(ModuleA, Feature1);
UTEST_FUNC2(ModuleA, Feature2);

In the test summary, tests with the same group name will be displayed together:

ModuleA:
[OK] Feature1
[OK] Feature2

Performance Timing

Enable performance timing to see how long each test takes:

UTEST_PROLOG();
UTEST_SHOW_PERFORMANCE(); // Enable timing
UTEST_FUNC(my_test);
UTEST_EPILOG();

Output will show timing information:

[OK] Test [my_test] succeeded (1.234ms)

Verbose Mode

Enable verbose mode to see test names before execution:

UTEST_PROLOG();
UTEST_ENABLE_VERBOSE_MODE(); // Show test names before execution
UTEST_FUNC(my_test);
UTEST_EPILOG();

Output will show test names before execution:

Running test: my_test
[OK] Test [my_test] succeeded (1.234ms)

For grouped tests:

Running test: GroupName::TestName
[OK] Test [GroupName::TestName] succeeded (1.234ms)

ASCII Checkmarks

For environments that don't support Unicode characters:

UTEST_PROLOG();
UTEST_USE_ASCII_CHECKMARKS(); // Use [OK]/[FAIL] instead of Unicode checkmarks
UTEST_FUNC(my_test);
UTEST_EPILOG();

String and Lambda Testing

The library now supports comprehensive string testing and modern C++ features:

// String testing with std::string and const char*
void test_strings() {
    std::string str = "hello";
    UTEST_ASSERT_EQUALS(str, "hello");
    UTEST_ASSERT_EQUALS("world", "world");
}

// Lambda and functor testing
void test_lambdas() {
    auto throwing_lambda = []() { throw std::exception(); };
    UTEST_ASSERT_THROWS(throwing_lambda);
    
    auto safe_lambda = []() { return 42; };
    UTEST_ASSERT_DOES_NOT_THROW(safe_lambda);
}

Compatibility Notes

C++11 Features Used

The library takes advantage of several C++11 features to provide clean, modern syntax:

  • Lambda expressions: For exception testing and complex test scenarios
  • Auto keyword: For type deduction in test code
  • Uniform initialization: For cleaner object construction
  • std::chrono: For high-precision timing measurements
  • nullptr: For safe null pointer testing
  • static_assert: For compile-time type checking
  • SFINAE with decltype: For template metaprogramming

Compiler Support

Tested with:

  • GCC 4.8+ (C++11 support)
  • Clang 3.3+ (C++11 support)
  • MSVC 2013+ (C++11 support)
  • Any compiler with full C++11 support

License

See LICENSE.txt

About

Unit testing (header-only) library for C++

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published