Property-based Testing in C++: Catch Bugs You Weren't Looking For

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

What if your unit tests are lying?

\n

You've written a hundred unit tests. They pass. The C++ code looks perfect. But when you run the application in production, it crashes with a segmentation fault on the 100,500th request. Sound familiar?

\n

Traditional unit tests only check what you thought of yourself. They are blind to scenarios that didn't occur to you. Property-based testing (or PBT) solves this problem radically: it does not check specific examples, but proves properties of your code for millions of random input values.

\n

In this article, we'll explore how to implement property-based testing in C++ using the RapidCheck library, and see how it catches bugs that ordinary unit tests miss. Ready to make your code truly suffer? Let's go.

\n\n

Property-based testing: philosophy in 30 seconds

\n

Imagine you are testing a sorting function. A typical test: sort([3,1,2]) == [1,2,3]. Okay, you checked one case.

\n

The property-based approach: "For any list of integers, after sorting the length does not change, the elements are in ascending order, and every element of the original list is present in the sorted one". The framework generates hundreds of random lists (including empty ones, with duplicates, with negative numbers) and checks these properties.

\n

The key idea: you describe invariants (properties) that must always hold, rather than specific inputs and outputs.

\n\n

When is PBT especially useful in C++?

\n
    \n
  • Algorithms and data structures (sorting, searching, graphs)
  • \n
  • Parsers and serializers (encoding/decoding)
  • \n
  • Mathematical functions (inverse operations, value ranges)
  • \n
  • Memory management (leaks, double free)
  • \n
  • Any code with clear invariants
  • \n
\n\n

RapidCheck: your new best friend

\n

There are several libraries for PBT in C++, but RapidCheck is the most mature and convenient. It is inspired by the Haskell library QuickCheck and integrates perfectly with Google Test and Catch2.

\n

Installation is simple: it is a header-only library, just copy the files from include/rapidcheck into your project. Or use Conan/vcpkg.

\n\n

First test: inverse operation property

\n

Let's say we have a function that encodes a string to base64 and decodes it back. What property is obvious? "Decoding after encoding returns the original string".

\n
#include <rapidcheck.h>\n#include <string>\n\nstd::string encode_base64(const std::string& input);\nstd::string decode_base64(const std::string& input);\n\nint main() {\n    rc::check("Decoding after encoding returns the original",\n              [](const std::string& original) {\n                  // String generator is built-in\n                  auto encoded = encode_base64(original);\n                  auto decoded = decode_base64(encoded);\n                  RC_ASSERT(decoded == original);\n              });\n    return 0;\n}\n
\n

What's happening here? RapidCheck generates random strings (including empty ones, with Unicode, with null bytes). For each one, it checks the property. If it finds a counterexample — it finds the minimal one (shrinking) that still breaks the test. This is gold: you get not just "there's a bug", but a specific reproducible case.

\n\n

Advanced properties: more than equality

\n

Monotonicity and idempotence

\n

For the remove_duplicates function:

\n
    \n
  • Idempotence: applying it twice does not change the result.
  • \n
  • Order doesn't matter: the resulting list contains the same elements as the original, but without duplicates.
  • \n
\n
#include <vector>\n#include <algo                

Blogs

Book Recommendations