Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
dad22ef
Add docs
franciszekjob Aug 28, 2025
4980f42
Update changelog
franciszekjob Aug 28, 2025
cff51bf
Fix tests
franciszekjob Aug 28, 2025
8f6e2b5
Fix tests
franciszekjob Aug 28, 2025
6430592
Update docs
franciszekjob Aug 28, 2025
c8fe288
Fix tests
franciszekjob Aug 28, 2025
d2ee2fe
Fix tests
franciszekjob Aug 28, 2025
a7c4a3e
Fix tests
franciszekjob Aug 28, 2025
01d7ae0
Fix tests
franciszekjob Aug 28, 2025
afa4e47
Add snippet configs
franciszekjob Aug 28, 2025
afe17af
Fix test attributes docs
franciszekjob Aug 28, 2025
ca03f80
Increase threshold in test
franciszekjob Aug 28, 2025
23b2375
Merge branch '1431-parametrized-tests' of https://github.com/foundry-…
franciszekjob Sep 17, 2025
41586a1
Split test package into multiple packages
franciszekjob Sep 17, 2025
4f2971f
Fix package name
franciszekjob Sep 17, 2025
471f37f
Rename "Complex" -> "Advanced"
franciszekjob Sep 17, 2025
a4553b2
Apply code review suggestion
franciszekjob Sep 17, 2025
6a98e7f
Fix tests
franciszekjob Sep 17, 2025
11f3164
Fix tests
franciszekjob Sep 17, 2025
c4534eb
Fix test
franciszekjob Sep 17, 2025
3bbb972
Update description
franciszekjob Sep 18, 2025
05541bd
Add note on possible test case name collisions
franciszekjob Sep 19, 2025
e871781
Merge branch '1431-parametrized-tests' into 1431-docs
franciszekjob Sep 19, 2025
37c8d8e
Merge branch '1431-parametrized-tests' of https://github.com/foundry-…
franciszekjob Sep 23, 2025
e2e2758
Apply code review suggestion
franciszekjob Sep 23, 2025
74ec926
Update example test
franciszekjob Sep 23, 2025
04efcf6
Merge branch '1431-docs' of https://github.com/foundry-rs/starknet-fo…
franciszekjob Sep 23, 2025
9428e2c
Remove unnecessary files
franciszekjob Sep 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support for `meta_tx_v0` syscall with cheatcode compatibility
- `snforge` now supports [oracles](https://docs.swmansion.com/cairo-oracle/) with `--experimental-oracles` flag.
- `--trace-components` flag to allow selecting which components of the trace to do display. Read more [here](https://foundry-rs.github.io/starknet-foundry/snforge-advanced-features/debugging.html#trace-components)
- `#[test_case]` attribute for parameterized testing. Read more [here](https://foundry-rs.github.io/starknet-foundry/snforge-advanced-features/parametrized-testing.html)

### Changed

Expand Down
2 changes: 1 addition & 1 deletion crates/forge/tests/data/test_case/tests/exit_first.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use test_case::fib;

#[test]
#[test_case(0, 1, 3)]
#[test_case(0, 1, 100000)]
#[test_case(0, 1, 500000)]
fn test_fib_with_threshold(a: felt252, b: felt252, n: felt252) {
let threshold: u256 = 10;
let res = fib(a, b, n);
Expand Down
14 changes: 14 additions & 0 deletions docs/listings/parametrized_testing_advanced/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "parametrized_testing_advanced"
version = "0.1.0"
edition = "2024_07"

[dependencies]
starknet = "2.12.0"
assert_macros = "2.12.0"

[dev-dependencies]
snforge_std = { path = "../../../snforge_std" }

[scripts]
test = "snforge test"
5 changes: 5 additions & 0 deletions docs/listings/parametrized_testing_advanced/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#[starknet::contract]
pub mod HelloStarknet {
#[storage]
struct Storage {}
}
20 changes: 20 additions & 0 deletions docs/listings/parametrized_testing_advanced/tests/example.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#[derive(Copy, Drop)]
struct User {
pub name: felt252,
pub age: u8,
}

#[generate_trait]
impl UserImpl of UserTrait {
fn is_adult(self: @User) -> bool {
return *self.age >= 18_u8;
}
}

#[test]
#[test_case(User { name: 'Alice', age: 20 }, true)]
#[test_case(User { name: 'Bob', age: 14 }, false)]
#[test_case(User { name: 'Josh', age: 18 }, true)]
fn test_is_adult(user: User, expected: bool) {
assert_eq!(user.is_adult(), expected);
}
14 changes: 14 additions & 0 deletions docs/listings/parametrized_testing_basic/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "parametrized_testing_basic"
version = "0.1.0"
edition = "2024_07"

[dependencies]
starknet = "2.12.0"
assert_macros = "2.12.0"

[dev-dependencies]
snforge_std = { path = "../../../snforge_std" }

[scripts]
test = "snforge test"
5 changes: 5 additions & 0 deletions docs/listings/parametrized_testing_basic/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#[starknet::contract]
pub mod HelloStarknet {
#[storage]
struct Storage {}
}
10 changes: 10 additions & 0 deletions docs/listings/parametrized_testing_basic/tests/example.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fn sum(x: felt252, y: felt252) -> felt252 {
return x + y;
}

#[test]
#[test_case(1, 2, 3)]
#[test_case(3, 4, 7)]
fn test_sum(x: felt252, y: felt252, expected: felt252) {
assert_eq!(sum(x, y), expected);
}
14 changes: 14 additions & 0 deletions docs/listings/parametrized_testing_fuzzer/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "parametrized_testing_fuzzer"
version = "0.1.0"
edition = "2024_07"

[dependencies]
starknet = "2.12.0"
assert_macros = "2.12.0"

[dev-dependencies]
snforge_std = { path = "../../../snforge_std" }

[scripts]
test = "snforge test"
5 changes: 5 additions & 0 deletions docs/listings/parametrized_testing_fuzzer/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#[starknet::contract]
pub mod HelloStarknet {
#[storage]
struct Storage {}
}
11 changes: 11 additions & 0 deletions docs/listings/parametrized_testing_fuzzer/tests/example.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fn sum(x: felt252, y: felt252) -> felt252 {
return x + y;
}

#[test]
#[test_case(1, 2)]
#[test_case(3, 4)]
#[fuzzer(runs: 10)]
fn test_sum(x: felt252, y: felt252) {
assert_eq!(sum(x, y), x + y);
}
1 change: 1 addition & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
* [Profiling](snforge-advanced-features/profiling.md)
* [Debugging](snforge-advanced-features/debugging.md)
* [Oracles](snforge-advanced-features/oracles.md)
* [Parametrized Tests](snforge-advanced-features/parametrized-testing.md)

---

Expand Down
133 changes: 133 additions & 0 deletions docs/src/snforge-advanced-features/parametrized-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Parametrized Testing

Sometimes, you want to run the same test logic with different inputs.
Instead of duplicating code into separate test functions, you can use parameterized tests.

Parameterized tests allow you to define multiple test cases for a single function by attaching the
`#[test_case]` attribute.

Each test case provides its own set of arguments, and `snforge` will automatically generate separate test instances for them.

## Basic Example

To turn a regular test into a parameterized one, add the `#[test_case(...)]` attribute above it.
You can provide any valid Cairo expressions as arguments.

Below is a simple example which checks addition of two numbers.

```rust
{{#include ../../listings/parametrized_testing_basic/tests/example.cairo}}
```

Now run:

<!-- { "package_name": "parametrized_testing_basic" } -->
```shell
$ snforge test
```

<details>
<summary>Output:</summary>

```shell
Collected 2 test(s) from parametrized_testing_basic package
Running 0 test(s) from src/
Running 2 test(s) from tests/
[PASS] parametrized_testing_basic_integrationtest::example::test_sum_1_2_3 ([..])
[PASS] parametrized_testing_basic_integrationtest::example::test_sum_3_4_7 ([..])
Tests: 2 passed, 0 failed, 0 ignored, [..] filtered out
```
</details>
<br>

## Naming Test Cases

Each parameterized test gets its own generated name. There are two ways to control it:

- **Unnamed test case** - the name is generated based on the function name and the arguments provided.

```rust
#[test_case(1, 2, 3)]
fn test_sum(x: felt252, y: felt252, expected: felt252) {
assert_eq!(sum(x, y), expected);
}
```
This will generate a test named `test_sum_1_2_3`.

- **Named test case** - you can provide a custom name for the test case using the `name` parameter.

```rust
#[test_case(name: "one_plus_two", 1, 2, 3)]
fn test_sum(x: felt252, y: felt252, expected: felt252) {
assert_eq!(sum(x, y), expected);
}
```
This will generate a test named `test_sum_one_plus_two`.

> 📝 **Note**
> For unnamed test cases, it's possible that two different input values of the same type can generate the same test case name.
> In such cases we emit a diagnostic error.
> To resolve it, simply provide an explicit `name` for the case.

## Advanced Example

Now let's look at an addvanced example which uses structs as parameters.

```rust
{{#include ../../listings/parametrized_testing_advanced/tests/example.cairo}}
```

Now run:

<!-- { "package_name": "parametrized_testing_advanced" } -->
```shell
$ snforge test
```

<details>
<summary>Output:</summary>

```shell
Collected 3 test(s) from parametrized_testing_advanced package
Running 3 test(s) from tests/
[PASS] parametrized_testing_advanced_integrationtest::example::test_is_adult_user_name_alice_age_20_true ([..])
[PASS] parametrized_testing_advanced_integrationtest::example::test_is_adult_user_name_josh_age_18_true ([..])
[PASS] parametrized_testing_advanced_integrationtest::example::test_is_adult_user_name_bob_age_14_false ([..])
Running 0 test(s) from src/
Tests: 3 passed, 0 failed, 0 ignored, [..] filtered out
```
</details>
<br>

## Combining With Fuzzer Attribute

`#[test_case]` can be freely combined with the `#[fuzzer]` attribute.

Below is an example in which we will fuzz the test but also run the specific defined cases.

```rust
{{#include ../../listings/parametrized_testing_fuzzer/tests/example.cairo}}
```

Now run:

<!-- { "package_name": "parametrized_testing_fuzzer" } -->
```shell
$ snforge test
```

<details>
<summary>Output:</summary>

```shell
Collected 3 test(s) from parametrized_testing_fuzzer package
Running 3 test(s) from tests/
[PASS] parametrized_testing_fuzzer_integrationtest::example::test_sum_1_2 ([..])
[PASS] parametrized_testing_fuzzer_integrationtest::example::test_sum_3_4 ([..])
[PASS] parametrized_testing_fuzzer_integrationtest::example::test_sum ([..])
Running 0 test(s) from src/
Tests: 3 passed, 0 failed, 0 ignored, 0 filtered out
Fuzzer seed: [..]
```
</details>
<br>
31 changes: 31 additions & 0 deletions docs/src/testing/test-attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Currently, those attributes are supported:
- `#[fork]`
- `#[fuzzer]`
- `#[disable_predeployed_contracts]`
- `#[test_case]`

> 📝 **Note**
>
Expand Down Expand Up @@ -154,3 +155,33 @@ Disables predeployment of default contracts in the test case.
Currently predeployed contracts are:
- `STRK`
- `ETH`

### `#[test_case]`

Generates multiple test cases from a single function by providing different sets of arguments.

Read more about parametrized tests [here](../snforge-advanced-features/parametrized-testing.md).

#### Usage

You can define multiple test cases by specifying different sets of arguments using the `#[test_case]` attribute.

```rust
#[test]
#[test_case(1, 2, 3)]
#[test_case(3, 4, 7)]
fn test_small_sum(a: felt252, b: felt252, expected: felt252) {
assert_eq!(a + b, expected);
}
```

Test cases can also be named for better identification in the test reports.

```rust
#[test]
#[test_case(name: "one_plus_two", 1, 2, 3)]
#[test_case(name: "three_plus_four", 3, 4, 7)]
fn test_small_sum(a: u32, b: u32, expected: u32) {
assert_eq!(a + b, expected);
}
```
Loading