Skip to main content
Learn how to write and run tests for your Leo programs using the built-in test framework.

Test Framework Overview

Leo includes a comprehensive test framework located in crates/test-framework/ that supports:
  • Unit tests within test programs
  • Integration tests in the tests/ directory
  • Expectation-based testing with automatic output comparison
  • Parallel test execution

Writing Unit Tests

Test Program Structure

Tests are written in separate .leo files in the tests/ directory:

Basic Test Example

Create a test program that imports your main program:
tests/test_my_project.leo
Test programs must import the program they’re testing and use the @test annotation on test functions.

Test Annotations

Leo provides several test annotations:
Marks a function as a test case:
Indicates the test should fail or panic:

Script Tests

You can also write standalone test scripts:
Scripts are lightweight test cases that don’t require a full program definition.

Assertions

assert_eq

Compare two values for equality:

assert_neq

Compare two values for inequality:

Complex Assertions

Test with complex data structures:

Running Tests

Run All Tests

Execute all tests in your project:

Run Specific Tests

Use the TEST_FILTER environment variable to run specific tests:
This runs only tests whose names contain “addition”.

Update Expectations

When test output changes intentionally, update expectation files:
Only use UPDATE_EXPECT=1 when you’ve verified the new output is correct. This overwrites all expectation files.

Test Framework Internals

The Leo test framework (from crates/test-framework/src/lib.rs):
1

Test Discovery

Scans the tests/{category} directory for .leo files:
2

Test Execution

Runs each test through the runner function:
3

Output Comparison

Compares output against expectation files in expectations/{category}/:

Parallel Execution

Tests run in parallel by default using Rayon:
For sequential execution, build with --features no_parallel.

Integration Testing

Testing with Dependencies

Test programs can have their own dependencies:
program.json

Testing with Multiple Programs

Test interactions between programs:
tests/test_interaction.leo

Testing Async and Finalize

Testing Mappings

Test programs that use on-chain storage:
Test the finalize logic:
tests/test_registry.leo

Testing Records

Test private record creation and manipulation:

Compiler Test Categories

The Leo compiler includes extensive tests organized by category:

Running Compiler Tests

Best Practices

1

Test One Thing

Each test should verify a single behavior:
2

Use Descriptive Names

Test names should describe what they verify:
3

Test Edge Cases

Include tests for boundary conditions:
4

Test Failure Cases

Verify error conditions with @should_fail:

CI/CD Integration

Leo tests integrate with continuous integration:

CircleCI Example

GitHub Actions Example

Next Steps