Hey everyone!
We’re Stan and @ulan, and we’ve been working on a new testing tool called ic-test – a command-line utility designed to simplify testing for cross-chain projects written in Rust. If you’re working with Internet Computer (IC) canisters and optionally EVM-based contracts, this might be something you’ll find useful.
What does ic-test
do?
In short, it automates the boilerplate and setup involved in writing canister and cross-chain integration tests:
- It reads the
dfx.json
andfoundry.toml
files to understand your canister and contract setup. - It generates Rust types from your Candid
.did
files. - It creates Solidity interfaces from your contract definitions.
- It sets up the basic API needed to interact with
.wasm
canisters and.json
contracts for test scenarios. - It uses
pocket-ic and
foundry` under the hood to actually run the tests.
How to use it?
- Install the tool:
cargo install ic-test
- Build your project:
dfx build
This ensures dfx
pulls all necessary dependencies and generates the .wasm
and .did
files under the .dfx
folder — which ic-test
uses to create the test setup.
- Finally, generate the new test project:
ic-test new tests
This creates a new workspace project called tests
. The test setup is saved in ic-test.json
.
Inside the tests
project you will see the bindings generated for each of the project canisters and EVM contracts. If some of the candid files was changed, you can regenerate the bindings with:
ic-test update
The tests.rs
file containing the actual test logic will not be overwritten by default — unless you explicitly run:
ic-test update --force
Example: Hello world test
Create a basic rust canister project:
dfx new hello --type rust
Generate the testing project:
ic-test new
Edit the tests.rs
to do the actual testing. Here’s an example tests.rs
for a simple “Hello World” project. After some basic adjustments, you might have:
// ...
async fn setup(test: IcpTest) -> Env {
let icp_user = test.icp.test_user(0);
let hello_backend = hello_backend::deploy(&icp_user).call().await;
let hello_frontend = hello_frontend::deploy(
&icp_user, // init args
None,
)
.call()
.await;
// Additional setup steps
// ...
Env {
test,
hello_backend,
hello_frontend,
}
}
#[tokio::test]
async fn test_greet() {
let Env {
test,
hello_backend,
hello_frontend,
} = setup(IcpTest::new().await).await;
// Call the greet method
let result: String = hello_backend.greet("ic-test".to_owned()).call().await;
assert_eq!(result, "Hello, ic-test!");
}
Now just run cargo test to see if the test is working.
Example of testing an EVM contract
For a more advanced example involving an EVM contract, check out the Co-processor example on the testing branch. You’ll need foundry installed.
git clone --branch testing https://github.com/wasm-forge/icp-evm-coprocessor-starter
dfx build
forge build
cargo test
Still a Work in Progress!
The tool is still under active development and it currently not as user-friendly as one might like, so things might change, and some edges might be rough — but that’s exactly why I’m reaching out.
I’d love your feedback!
If you try it out and something doesn’t work, or if there’s a feature you wish it had, please let me know.
Thanks for reading! Looking forward to hearing your thoughts and seeing how you use ic-test
in your projects.
Cheers!
Stan