-
Notifications
You must be signed in to change notification settings - Fork 245
Add fuzz testing intro with link to Rendezvous docs #1713
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
9b5b0fd
Add fuzz testing intro with link to Rendezvous docs
moodmosaic d255308
Expand fuzz-testing to include must-have Rendezvous info
BowTiedRadone 5e1948e
Link Fuzz Testing item to fuzz-testing section
BowTiedRadone fe9a798
Add `clarunit` bullet in fuzz-testing `README`
BowTiedRadone File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Testing Smart Contracts | ||
|
||
Smart contracts are immutable once deployed. Bugs are permanent. Test them | ||
thoroughly. | ||
|
||
This section covers testing Clarity contracts. | ||
|
||
* [Fuzz Testing](./fuzz-testing.md): Use Rendezvous to hammer your contract with random | ||
inputs. It helps expose edge cases and vulnerabilities. | ||
moodmosaic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* [Clarity Unit Testing](https://github.com/stacks-network/clarunit) | ||
|
||
More guides will follow. |
131 changes: 131 additions & 0 deletions
131
guides-and-tutorials/testing-smart-contracts/fuzz-testing.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# Fuzz Testing with Rendezvous | ||
|
||
Smart contracts on Stacks are immutable. Bugs are forever. Test early. Test | ||
often. Fuzzing finds edge cases that unit tests often miss. | ||
|
||
## What is Fuzz Testing? | ||
|
||
Fuzzing hits your code with random inputs. It helps uncover unexpected | ||
behavior and subtle bugs. Unlike unit tests, it explores paths you didn't | ||
think of. | ||
|
||
Rendezvous (`rv`) is a Clarity fuzzer. It supports: | ||
|
||
### Property-Based Testing | ||
|
||
You extract properties about your smart contract using Clarity. Rendezvous checks them multiple times with random inputs, in a stateful manner (the smart contract's state is not refreshed during the run). | ||
|
||
**What is a property?** | ||
|
||
A property is a universal truth about your smart contract's state, functions, etc. | ||
|
||
**How to extract a property?** | ||
|
||
Say that your smart contract has a function that reverses a list of `uint`s. In this case, one property can be that "reversing a list twice returns the original list". The property will look like this: | ||
|
||
```clarity | ||
(define-public (test-reverse-list (seq (list 127 uint))) | ||
(begin | ||
(asserts! | ||
(is-eq seq | ||
(reverse-uint | ||
(reverse-uint seq) | ||
) | ||
) | ||
(err u999) | ||
) | ||
(ok true) | ||
) | ||
) | ||
``` | ||
|
||
**Making your property valid for Rendezvous** | ||
|
||
> For a property to be cosidered valid by Rendezvous, it has to comply with the following rules: | ||
> | ||
> - Function name starts with `test-` | ||
> - Function is declared as `public` | ||
> - Test passes when it returns `(ok true)` | ||
> - Test would be discarded if it returned `(ok false)` | ||
> - Test fails if it returns an error or throws an exception | ||
|
||
--- | ||
|
||
### Invariant Testing | ||
|
||
You define read-only conditions in Clarity that must always hold true. Rendezvous attempts to create state transitions in your smart contract and continuously checks the conditions you defined to hold. | ||
|
||
**What is an invariant?** | ||
|
||
An invariant is a general truth regarding your smart contract's internal state. It will not be able to mutate the state, its role being solely to check the integrity of the state. | ||
|
||
**How to extract an invariant?** | ||
|
||
Say that you have a counter contract, having functions to `increment` and `decrement`. In this case, you could use the Rendezvous `context` to extract an invariant regarding your smart contract's internal state: | ||
|
||
```clarity | ||
(define-read-only (invariant-counter-gt-zero) | ||
(let | ||
( | ||
(increment-num-calls | ||
(default-to u0 (get called (map-get? context "increment"))) | ||
) | ||
(decrement-num-calls | ||
(default-to u0 (get called (map-get? context "decrement"))) | ||
) | ||
) | ||
(if | ||
(<= increment-num-calls decrement-num-calls) | ||
true | ||
(> (var-get counter) u0) | ||
) | ||
) | ||
) | ||
``` | ||
|
||
**Making your invariant valid for Rendezvous** | ||
|
||
> For an invariant to be cosidered valid by Rendezvous, it has to complain to the following ruleset: | ||
> | ||
> - Function name starts with invariant- | ||
> - Function is declared as read-only (not public) | ||
> - Function returns a boolean value (true if the invariant holds, false if violated) | ||
> - The test can use the special context map to access execution history | ||
|
||
## Why Test in Clarity? | ||
|
||
Rendezvous tests run in Clarity, just like your contracts. | ||
|
||
1. Tests operate under the exact same constraints as production code. | ||
2. Better understanding of Clarity. | ||
3. No need to expose internals as public functions. | ||
4. Fewer tools to manage. | ||
|
||
## Getting Started | ||
|
||
Put tests next to contracts. Rendezvous will find them. | ||
|
||
``` | ||
my-project/ | ||
├── Clarinet.toml | ||
├── contracts/ | ||
│ ├── my-contract.clar # Contract | ||
│ ├── my-contract.tests.clar # Tests | ||
└── settings/ | ||
└── Devnet.toml | ||
``` | ||
|
||
### Installation | ||
|
||
To install Rendezvous as a dependency in your project, use `npm`: | ||
|
||
``` | ||
npm install @stacks/rendezvous | ||
``` | ||
|
||
This will add Rendezvous to your project's `node_modules` and update your `package.json`. | ||
|
||
## Rendezvous Docs | ||
|
||
See full docs at: | ||
https://stacks-network.github.io/rendezvous/ |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.