How to Write and Run Unit Tests with `forc test` in Sway

The forc test command compiles and executes all functions annotated with #[test] in a Sway package, running them on the Fuel VM and reporting pass/fail status, gas usage, and optional logs.

The forc test command is the official test harness for the Sway language, maintained in the FuelLabs/sway repository. It provides a zero-configuration workflow for unit testing smart contracts and scripts by compiling each #[test] function as an independent entry point and executing it within the Fuel VM environment.

Writing Tests for forc test

Basic Unit Tests

Mark any function with the #[test] attribute to register it as a test entry point. The function must take no arguments and return unit ().

#[test]
fn test_meaning_of_life() {
    assert(6 * 7 == 42);
}

Testing Revert Conditions

Use #[test(should_revert)] when you expect a test to fail by reverting. The test passes only if execution triggers a rvrt instruction.

#[test(should_revert)]
fn test_fails_on_wrong_result() {
    // This will revert because the assertion is false.
    assert_eq(6 * 6, 42);
}

To assert a specific revert code, provide the 64-bit decimal value as a string:

#[test(should_revert = "18446744073709486084")]
fn test_specific_revert() {
    assert_eq(6 * 6, 42);
}

Testing Contract Calls

When testing contract logic, forc test automatically builds the contract without tests first to compute CONTRACT_ID, then rebuilds with tests and injects that identifier into the test namespace.

contract;

abi MyContract {
    fn greet() -> bool;
}

impl MyContract for Contract {
    fn greet() -> bool {
        true
    }
}

#[test]
fn test_contract_call() {
    let caller = abi(MyContract, CONTRACT_ID);
    let result = caller.greet {}();
    assert(result == true);
}

Logging Inside Tests

Use the log() function to emit values during test execution. Logs are captured as Log or LogData receipts on the Fuel VM.

script;

fn main() {}

#[test]
fn test_with_logs() {
    let a = 10;
    log(a);
    let b = 30;
    log(b);
    assert_eq(a, 10);
    assert_eq(b, 30);
}

Running Tests with forc test

Basic Invocation

Execute all tests in the current package:

forc test

This compiles the package with the is_test flag set in sway-core/src/build_config.rs and runs each test binary on the Fuel VM.

Filtering Tests

Run only tests whose names contain a specific substring:

forc test mean

Run a single test by exact name match:

forc test --filter-exact test_meaning_of_life

The filtering logic is implemented via TestFilter in forc/src/cli/commands/test.rs.

Controlling Parallelism

By default, forc test uses as many threads as available CPU cores. Force single-threaded execution for deterministic log ordering:

forc test --test-threads 1

This maps to TestRunnerCount in the forc_test crate.

Output and Debugging Options

Control the verbosity and format of test results:

  • -l / --logs — Decode and print Log/LogData receipts (see print_test_output in forc/src/cli/commands/test.rs).
  • --raw-logs — Display raw log receipts as JSON.
  • --pretty — Pretty-print raw JSON logs.
  • --reverts — Show revert codes and error messages for failing or should_revert tests.
  • --dbgs — Print debug output from dbg! captures.
  • --silent — Suppress the summary output (useful in CI pipelines).

Example combining multiple flags:

forc test --logs --raw-logs --pretty --reverts

Gas Usage Reporting

forc test reports gas consumed for each test (e.g., (..., 512 gas)). Override the default gas cost table with:

forc test --gas-costs testnet

Valid options include built-in, mainnet, testnet, or a path to a custom JSON file.

How forc test Works Internally

The test harness follows a multi-stage pipeline defined in the forc-test crate and orchestrated from forc/src/cli/commands/test.rs:

  1. CLI Parsing — The Command struct in test.rs defines all flags (filtering, threading, output options) and the exec entry point.
  2. Build Stepforc_test::build(opts) compiles each #[test] function as an independent entry point. The is_test flag in sway-core/src/build_config.rs enables test-specific compilation paths.
  3. Executionbuilt_tests.run(...) spawns the Fuel VM for each compiled artifact, respecting TestRunnerCount for parallelism.
  4. Result Processingprint_tested_pkg iterates over TestResult structs, formatting pass/fail markers, gas usage, and delegating to print_test_output for logs.
  5. Exit Code — If any test fails, exec returns exit code 101; otherwise 0 (lines 57–65 of test.rs).

Quick Reference Cheat Sheet


# Run all tests

forc test

# Run tests matching a substring

forc test math

# Run exact test name

forc test --filter-exact test_math_addition

# Single-threaded execution

forc test --test-threads 1

# Show logs and revert details

forc test --logs --reverts

# Pretty-print raw logs

forc test --raw-logs --pretty

# Custom gas costs

forc test --gas-costs testnet

# Silent mode for CI

forc test --silent

Summary

  • Annotate test functions with #[test] or #[test(should_revert)] to mark them as entry points for forc test.
  • The command compiles each test as an independent binary, executes it on the Fuel VM, and reports gas usage alongside pass/fail status.
  • Use --filter-exact to run single tests and --test-threads to control parallelism.
  • Access logs with --logs or --raw-logs, and inspect revert codes with --reverts.
  • The implementation resides in forc/src/cli/commands/test.rs and the forc-test crate, using the is_test flag in sway-core/src/build_config.rs to enable test-specific compilation.

Frequently Asked Questions

How do I run a single specific test with forc test?

Use the --filter-exact flag followed by the full function name. For example, forc test --filter-exact test_meaning_of_life runs only that function. Without this flag, providing a positional argument acts as a substring filter, running all tests whose names contain the provided text.

Can I view logs from tests that pass?

By default, logs are suppressed for passing tests. To view them, add the -l or --logs flag to decode and display Log and LogData receipts. For raw VM receipt data, use --raw-logs, and combine with --pretty for formatted JSON output.

What exit code does forc test return on failure?

The command exits with status 101 if any test fails, and 0 on complete success. This behavior is defined in the exec function within forc/src/cli/commands/test.rs (lines 57–65) and follows Rust’s testing convention, making it suitable for CI pipelines that check exit status.

How do I test that a function reverts with a specific error code?

Annotate the test with #[test(should_revert = "18446744073709486084")], providing the 64-bit decimal representation of the expected revert code. The test harness compares the actual revert code from the VM against this value, and the test passes only if they match.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →