In Brief
The purpose of the library is to test general properties of a program rather than very specific examples as you would with unit tests.
- When writing a
checkitotest (called acheck), you first construct a generator by specifying the bounds that make sense for the inputs (ex: a number in the range10..100, an alpha-numeric string, a vector off64, etc.). - Generators can produce arbitrary complex values with their combinators, in a similar way that
Iterators can. - Given a proper generator,
checkitowill sample the input space to find a failing case for your test. - Once a failing case is found,
checkitowill try to reduce the input to the simplest version of it that continues to fail (using a kind of binary search of the input space) to make the debugging process easier. - For generators with a small number of possible values (e.g.,
bool, a short range, or a tuple of small types),checkitowill automatically run exhaustively to cover all possible values. For larger or infinite input spaces, it samples randomly. This is meant as a complement to other testing strategies. - It is recommended to write a regular unit test with the exact failing input to prevent a regression and to truly guarantee that the failing input is always tested.
Main Concepts
The library is built around a few core traits:
Generate: is implemented for many of rust's standard types and allows the generation of any random composite/structured data through combinator (such as tuples,Any,Map,Flattenand more). It is designed for composability and its usage should feel like working withIterators.Shrink: tries to reduce a generated sample to a 'smaller' version of it while maintaining its constraints (ex: a sampleusizein the range10..100will never be shrunk below10). For numbers, it means bringing the sample closer to 0, for vectors, it means removing irrelevant items and shrinking the remaining ones, and so on.Prove: represents a desirable property of a program under test. It is used mainly in the context of theCheck::checkorChecker::checkmethods and it is the failure of a proof that triggers the shrinking process. It is implemented for a couple of standard types such as(),boolandResult. Apanic!()is also considered as a failing property, thus standardassert!()macros (or any other panicking assertions) can be used to check the property.Check: A trait (implemented for allGeneratetypes) that provides the main entry points for running property tests:checkandchecks.
Environment Variables
The behavior of the test runner can be configured through environment variables, which is particularly useful for CI environments or for debugging specific issues.
Generation
CHECKITO_GENERATE_COUNT: Overrides the number of test cases to run. Example:CHECKITO_GENERATE_COUNT=1000 cargo testCHECKITO_GENERATE_SIZE: Sets a fixed generation size (0.0to1.0). Example:CHECKITO_GENERATE_SIZE=1.0 cargo testCHECKITO_GENERATE_SEED: Sets the initial seed for the random number generator, allowing for reproducible test runs.CHECKITO_GENERATE_ITEMS: Sets whether to display passing generation items (trueorfalse).
Shrinking
CHECKITO_SHRINK_COUNT: Overrides the maximum number of shrink attempts.CHECKITO_SHRINK_ITEMS: Sets whether to display passing shrink items (trueorfalse).CHECKITO_SHRINK_ERRORS: Sets whether to display failing shrink items (trueorfalse).
Cheat Sheet
use *;
/// The `#[check]` attribute is designed to be as thin as possible and
/// everything that is expressible with it is also ergonomically expressible as
/// _regular_ code (see below). Each `#[check]` attribute expands to a single
/// function call.
///
/// An empty `#[check]` attribute acts just like `#[test]`. It is allowed for
/// consistency between tests.
/// The builtin `letter()` generator will yield ascii letters.
///
/// This test will be run many times with different generated values to find a
/// failing input.
/// Ranges can be used as generators and will yield values within its bounds.
///
/// A [`bool`] can be returned and if `true`, it will be considered as evidence
/// that the property under test holds.
/// Regexes can be used and validated either dynamically using the [`regex`]
/// generator or at compile-time with the [`regex!`] macro.
///
/// Usual panicking assertions can be used in the body of the checking function
/// since a panic is considered a failed property.
/// The `_` and `..` operators can be used to infer the [`FullGenerate`]
/// generator implementation for a type. Specifically, the `..` operator works
/// the same way as slice match patterns.
///
/// Since this test will panic, `#[should_panic]` can be used in the usual way.
/// `color = false` disables coloring of the output.
/// `verbose = true` will display all the steps taken by the [`check::Checker`]
/// while generating and shrinking values.
///
/// The shrinking process is pretty good at finding minimal inputs to reproduce
/// a failing property and in this case, it will always shrink values over
/// `1000` to exactly `1000`.
/// Multiple checks can be performed.
///
/// If all generators always yield the same value, the check becomes a
/// parameterized unit test and will run only once.
/// Generics can be used as inputs to the checking function.
///
/// [`Generate::map`] can be used to map a value to another.
/// Use tuples to combine generators and build more complex structured types.
/// Alternatively implement the [`FullGenerate`] trait for the [`Person`]
/// struct.
///
/// Any generator combinator can be used here; see the other examples in the
/// _examples_ folder for more details.
///
/// Disable `debug` if a generated type does not implement [`Debug`] which
/// removes the only requirement that `#[check]` requires from input types.
/// The `#[check]` attribute essentially expands to a call to [`Check::check`]
/// with pretty printing. For some more complex scenarios, it may become more
/// convenient to simply call the [`Check::check`] manually.
///
/// The [`Generate::any`] combinator chooses from its inputs. The produced
/// `Or<..>` preserves the information about the choice but here, it can be
/// simply collapsed using [`Generate::unify<T>`].
See the examples and tests folder for more detailed examples.
Contribute
- If you find a bug or have a feature request, please open an issues.
checkitois actively maintained and pull requests are welcome.- If
checkitowas useful to you, please consider leaving a star!