Skip to main content

Testing

Writing tests for Soroban contracts involves writing Rust code using the test facilities and toolchain that you'd use for testing any Rust code.

Given a simple contract like the contract demonstrated in Write a Contract, a simple test will look like this.

#![cfg(test)]

use super::{Contract, ContractClient};
use soroban_sdk::{symbol, vec, BytesN, Env};

#[test]
fn test() {
let env = Env::default();
let contract_id = BytesN::from_array(&env, &[0; 32]);
env.register_contract(&contract_id, Contract);
let client = ContractClient::new(&env, &contract_id);

let words = client.hello(&symbol!("Dev"));
assert_eq!(
words,
vec![&env, symbol!("Hello"), symbol!("Dev"),]
);
}
info

The above example is a Rust unit test that lives inside the src/ directory. Note that if you place the test in the tests/ directory it becomes a Rust integration test with the test being compiled separately. Integration tests require #![cfg(feature = "testutils")] at the top of the file and to be run with the testutils feature enabled, e.g. cargo test --features testutils, to enable the generated Soroban test utilities.

In any test the first thing that is always required is an Env, which is the Soroban environment that the contract will run inside of.

let env = Env::default();

Contracts must be registered with the environment with a contract ID, which is a 32-byte value. In many cases it is sufficient to use a simple zero ID, however if the test will deploy the contract multiple times, or deploy multiple contracts, each should use their own IDs.

let contract_id = BytesN::from_array(&env, &[0; 32]);
env.register_contract(&contract_id, Contract);

All public functions within an impl block that is annotated with the #[contractimpl] attribute have a corresponding function generated in a generated client type. The client type will be named the same as the contract type with Client appended. For example, in our contract the contract type is Contract, and the client is named ContractClient.

let client = ContractClient::new(&env, &contract_id);
let words = client.hello(&symbol!("Dev"));

The values returned by functions can be asserted on:

assert_eq!(
words,
vec![&env, symbol!("Hello"), symbol!("Dev"),]
);

Run the Tests‚Äč

Run cargo test and watch the contract run. You should see the following output:

cargo test
running 1 test
test test::test ... ok

Try changing the values in the test to see how it works.