opensourceprojects.dev

A broadsheet for software that doesn't ask for your email

Property-based testing for C++ with shrinking and STL support
GitHub RepoImpressions2

Project Description

View on GitHub

Property-Based Testing in C++ Without the Clunk

You've probably written a test that checks one specific input against one specific output, then moved on. But what about the inputs you didn't think to write? Property-based testing flips the script—instead of enumerating cases, you state a rule that should always hold, and let the framework hunt for the input that breaks it. RapidCheck brings that approach to C++, and it's built with shrinking so the failures you get back are actually readable.

What It Does

RapidCheck is a C++ framework for property-based testing, inspired by QuickCheck and similar tools. The idea is straightforward: you declare facts about your code—properties that should be true given certain preconditions—and RapidCheck generates random test data to try to falsify them. If it finds a failing case, it then shrinks that case down to the smallest input that still fails, and shows you that as a counterexample. For an integer input, for instance, it'll try to hand you the smallest integer that breaks your property.

The framework makes extensive use of C++11 and requires a compliant compiler. Continuous integration runs against Clang 3.5, GCC 4.9, and Visual Studio 2015, so anything newer should work fine. It's built with CMake, and if your project already uses CMake, you can drop it in as a subdirectory and link against rapidcheck to get both include directories and linking set up.

Why It's Cool

The author is upfront about the motivation: existing property-based testing implementations felt "a bit clunky" or were missing essentials like shrinking. RapidCheck is a response to that, and a few things stand out.

  • Shrinking is the headline. Finding a failing case is only half the job—a random failing input is often useless for debugging. RapidCheck automatically minimizes the counterexample, which is the difference between "here's a 40-element vector that fails" and "here's the two-element vector that fails." That's the feature the author calls out as essential and often missing elsewhere.

  • It's written for C++ developers. Properties are written imperatively in a way that makes sense for the language, rather than forcing you into some awkward functional style. The quick-start example is a lambda that takes a std::vector<int>, double-reverses it, and asserts equality with RC_ASSERT—no ceremony beyond that.

  • STL support is real. Maps, sets, and other standard types have great built-in support, which matters because those are the containers you're actually passing around. You don't have to hand-roll generators for common types.

  • Combinators for custom generators. When the built-in generators aren't enough, advanced combinators let you compose your own. And if you need to test sequences of operations rather than single values, there's stateful testing based on commands, in the vein of Erlang QuickCheck.

  • It plays nice with your existing setup. Integrations exist for Boost Test, Google Test, and Google Mock, so you're not abandoning your current test suite to adopt it.

How to Try It

Getting started is mostly a CMake affair. If your project uses CMake, add RapidCheck as a subdirectory:

add_subdirectory("path/to/rapidcheck")
target_link_libraries(my_target rapidcheck)

Then write a property. The canonical first example tests a reversal function—double reversal should yield the original list:

#include <rapidcheck.h>

#include <vector>
#include <algorithm>

int main() {
  rc::check("double reversal yields the original value",
            [](const std::vector<int> &l0) {
              auto l1 = l0;
              std::reverse(begin(l1), end(l1));
              std::reverse(begin(l1), end(l1));
              RC_ASSERT(l0 == l1);
            });

  return 0;
}

The check function takes an optional description and a callable implementing the property. Any parameters to that callable get randomly generated, and RC_ASSERT works like any assert macro—if the condition is false, the property is falsified. Running it prints the configuration (including the random seed, which is handy for reproducing failures) and reports how many tests passed. When something fails, you'll see how many tests ran before the failure and how many shrinks it took to minimize the counterexample.

The README points to a full User Guide for the deeper material—combinators, stateful testing, and framework integration. You can find the project and the guide at github.com/emil-e/rapidcheck.

Final Thoughts

RapidCheck is a focused tool that solves a specific problem well: bringing property-based testing to C++ without the awkwardness the author found in alternatives, and with shrinking built in from the start. If you're already comfortable with QuickCheck-style testing in other languages and miss it in C++, or if you've got pure functions and data structures that would benefit from randomized input, it's worth a look. It assumes a modern compiler and a CMake-based workflow, so factor that in. For everyone else, it's a solid example of a framework built by someone who wanted a better version of what already existed—and then made it.

Back to Projects
Project ID: 1493fa18-e928-4a12-8094-e9b00c60b031Last updated: October 17, 2026 at 02:48 AM