Trompeloeil

Language: CPP

Testing

Trompeloeil was created by Björn Fahller to bring a clean, type-safe, and powerful mocking library to modern C++. Its name comes from the French term 'trompe-l'œil', meaning 'deceive the eye', reflecting the way mocks pretend to be real objects during testing. Today, Trompeloeil is used widely in C++ projects alongside testing frameworks like Catch2, doctest, and Google Test.

Trompeloeil is a modern C++14 mocking framework for unit testing. It provides a type-safe, expressive API for creating mocks, setting expectations, and verifying interactions between objects.

Installation

cmake: find_package(Trompeloeil CONFIG REQUIRED)
vcpkg: vcpkg install trompeloeil
conan: conan install trompeloeil
manual: Download and include trompeloeil.hpp (header-only)

Usage

Trompeloeil allows developers to create mocks of interfaces or abstract classes, define expectations on method calls, and verify those expectations at runtime.

Basic mock interface

#include <trompeloeil.hpp>
#include <catch2/catch_test_macros.hpp>

struct Printer {
    virtual void print(const std::string& msg) = 0;
    virtual ~Printer() = default;
};

struct MockPrinter : Printer {
    MAKE_MOCK1(print, void(const std::string&), override);
};

TEST_CASE("Printer prints a message") {
    MockPrinter printer;
    REQUIRE_CALL(printer, print("Hello"));
    printer.print("Hello");
}

Defines a mock `Printer` and verifies that `print("Hello")` was called once.

Multiple expectations

REQUIRE_CALL(printer, print("A"));
REQUIRE_CALL(printer, print("B"));

printer.print("A");
printer.print("B");

Verifies that multiple calls happen in the expected way.

Controlling call counts

ALLOW_CALL(printer, print(trompeloeil::_)).TIMES(2);

printer.print("Hi");
printer.print("Bye");

Allows a method to be called exactly two times with any string.

Returning values

struct Reader {
    virtual int read() = 0;
};

struct MockReader : Reader {
    MAKE_MOCK0(read, int(), override);
};

MockReader reader;
REQUIRE_CALL(reader, read()).RETURN(42);
CHECK(reader.read() == 42);

Mocks a method that returns a value and specifies the return.

Sequences of calls

trompeloeil::sequence seq;
REQUIRE_CALL(printer, print("First")) .IN_SEQUENCE(seq);
REQUIRE_CALL(printer, print("Second")) .IN_SEQUENCE(seq);

printer.print("First");
printer.print("Second");

Ensures methods are called in a specific order.

Error Handling

Unexpected call: Use `ALLOW_CALL` for calls that are optional, or add missing `REQUIRE_CALL` expectations.
Call count mismatch: Check `.TIMES()` or ensure test logic calls the mock the expected number of times.
Segfaults on mock usage: Ensure mocked objects outlive their expectations and are not destroyed prematurely.

Best Practices

Use Trompeloeil with a test framework like Catch2 or Google Test for assertions.

Keep mocks small and focused on the interaction under test.

Use `ALLOW_CALL` for setup, and `REQUIRE_CALL` to enforce critical expectations.

Leverage `.TIMES()`, `.RETURN()`, and `.IN_SEQUENCE()` to fine-tune behavior.

Prefer mocking interfaces or abstract base classes rather than concrete implementations.