Quint Connect
A model-based testing framework for Rust that connects Quint specifications with Rust applications.
Overview
Quint Connect enables rigorous testing of Rust code against formal specifications written in Quint. By automatically generating traces from your Quint specifications and replaying them against your Rust implementation, you can verify that your code behaves exactly as specified.
Key Features
- Automatic Trace Generation: Generates test cases from Quint specifications
- State Validation: Automatically verifies that implementation state matches specification state
- Model-Based Testing: Leverage Quint's powerful specification language for comprehensive testing
- Declarative Test Definition: Simple macros for defining model-based tests
- Detailed Error Reporting: Clear diffs when implementation diverges from specification
Requirements
- Rust 1.70 or later
- Quint installed and available in PATH
Quick Start
1. Define Your Specification
Write your system specification in Quint (e.g., spec.qnt).
2. Implement the Test Driver
Create a test driver that connects your Rust implementation to the test framework:
use *;
use Deserialize;
3. Create Tests
Use the provided macros to create model-based tests:
use *;
// Run a single test as specified by a Quint run
// Run multiple traces in simulation mode
4. Run Test
Run tests with:
Increase verbosity to see step's actions and nondeterministic choices available:
QUINT_VERBOSE=1
Tips and Tricks
Nondeterminism
Quint detects nondeterminism in the specification's step action. For example:
action step = any {
action1,
// ...
}
action action1 = {
nondet node = NODES.oneOf()
// ...
}
When collecting traces, Quint keeps track of action names and their set of
nondet values as it runs simulations or tests. These become available to Quint
Connect automatically. However, if an anonymous action is detected, Quint
Connect will fail to run steps:
action step = any {
action1,
all { // <- anonymous action!
action2,
action3
}
}
In those cases, simply rewrite the spec so that all actions in step are
properly named:
action step = any {
action1,
action2_and_3
}
action action2_and_3 = all {
action2,
action3
}
Enums
Quint sum types are serialized by Quint as records with the tag and value
fields representing the type variant and its arguments, respectively. For
example:
type SumType =
| Variant1
| Variant2
// Serializes as:
// { tag: "Variant1", value: [] }
The previous Quint sum type can be deserialized in Rust with:
use Deserialize;
Sum types with associated values require specifying serde's content
attribute. For example:
type SumType =
| Variant1(int)
| Variant2(str)
The sum type above must be deserialized as:
use Deserialize;
// <- note the `content` attribute
Optional Fields
Optional types in Quint are defined as a sum type:
type Option[a] = Some(a) | None
The itf crate has utilities to help deserializing optional fields:
use Deserialize;
use ;
Configuration
Driver Configuration
In some cases the state that you want to check is nested within some global
variable. To narrow down the verifiable state, override the Driver config
method with the path to the variable that holds the state to check:
use *;
Similarly, in some scenarios the user may choose to track nondeterminism manually other than using Quint's builtin variables. In those cases, track nondeterminism as a sum type where each variant holds a record containing nondeterministic choices, then specify its path in the driver's configuration:
use *;
These driver configurations are most commonly used when checking traces from
specifications using the Choreo
library. See the two_phase_commit example in the examples folder
for details on how its implementation is checked with Quint connect.
Verbosity Control
Set the QUINT_VERBOSE environment variable to control output verbosity:
QUINT_VERBOSE=0: Minimal outputQUINT_VERBOSE=1: Show trace and step informationQUINT_VERBOSE=2: Show detailed state and step derivation
Reproducible Tests
Failed tests display the random seed used:
Reproduce this error with `QUINT_SEED=42`
Set the seed to reproduce exact test traces:
QUINT_SEED=42
Examples
See the connect/examples/ directory for complete examples:
- tictactoe: A simple tic-tac-toe game implementation
- two_phase_commit: A simplified version of the two-phase commit protocol using Choreo
License
Copyright 2025 Informal Systems Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.