Implement stateful testing with rc::state
masterStandard RapidCheck properties test simple inputs. For stateful systems (like data structures), you must test sequences of operations. RapidCheck provides the rc::state framework to handle this by requiring two components:
- A Model: A simple struct representing the expected state of the System Under Test (SUT). This allows RapidCheck to track state and generate valid command sequences without running the actual SUT, which is critical for efficient shrinking.
- Commands: Subclasses of
rc::state::Command<Model, Sut>that represent operations performed on the system.
To use this, you implement commands that define how to update the model, how to run the operation on the SUT, and what preconditions must be met.
// Example of a simple model
struct FastKvStoreModel {
std::map<std::string, std::string> data;
};
// Example of a command
struct Remove : rc::state::Command<FastKvStoreModel, FastKvStore> {
std::string key;
void checkPreconditions(const FastKvStoreModel &s0) const override {
RC_PRE(s0.data.count(key) != 0);
}
void apply(FastKvStoreModel &s0) const override {
s0.data.erase(key);
}
void run(const FastKvStoreModel &s0, FastKvStore &sut) const override {
sut.remove(key);
RC_ASSERT(!sut.hasKey(key));
}
void show(std::ostream &os) const override {
os << "Remove(" << key << ")";
}
};