CW Multi Test
Cw Multi Test is a rust-based test framework that allows developers to test for multi-contract interactions without having to dispatch messages, storage and other variables themselves. With cw-orchestrator, most of the cw-multi-test
logic is abstracted away, but you can still learn more about the framework here.
Quick Start
The cw-multi-test
integration comes at no extra cost for the developer. Creating a test environement in cw-orchestrator that leverages cw-multi-test
goes along the lines of:
use cw_orch::prelude::*;
use cosmwasm_std::Addr;
let sender = Addr::unchecked("juno16g2rahf5846rxzp3fwlswy08fz8ccuwk03k57y");
let mock = Mock::new(&sender);
NOTE: When using
cw-multi-test
, the addresses ARE NOT validated like on a live chain. Therefore, you can use any string format for designating addresses. For instance,Addr::unchecked("my-first-sender")
is a validcw-multi-test
address.
NOTE: When using
cw-multi-test
, NO gas fees are charged to the sender address.
Interacting with contracts
You can then use the resulting Mock
variable to interact with your contracts:
let contract_counter = CounterContract::new("mock:contract_counter", mock);
let upload_res = contract_counter.upload();
upload_res.unwrap();
When executing contracts in a cw-multi-test
environment, the messages and sub-messages sent along the Response of an endpoint, will be executed as well.
This environment mocks the actual on-chain execution exactly
This environment uses the actual functions of your contract without having to compile them into WASM. When you are calling
upload
with this environment, no wasm files are included in the test environment. This allows for better debugging of your contract code.
If you are using the customizable Interface Macro, you will need to have implemented the
wrapper
function for interacting the theMock
environment. This function wil allow you to “connect” your contract endpoints to yourContract
struct See the dedicated page for more details.
NOTE: Keep in mind that
cw-multi-test
is based solely in rust and that a lot of actual blockchain modules are not mocked in the environment. The main cosmos modules are there (Bank, Staking), but some very useful ones (tokenfactory, ibc) as well as Stargate messages are not supported by the environment.
Cloning
When cloning a cw_multi_test environment, you are not cloning the entire environment, but instead you are creating a new Mock
typed variable with the same underlying cw_multi_test::App
object reference. This is useful for objects that require to pass the chain as an object rather than by reference.
The underlying cw_multi_test::App
object is however not clonable.
Additional tools
The Mock
test environment allows you to change application variables (such as the balance of an account) using wrappers around the underlying cw_multi_test::App
object. Here are some examples of those wrappers in context:
let new_sender = Addr::unchecked("entirely-new-sender");
mock.set_balance(&new_sender, coins(100_000, "ujunox"))
.unwrap();
// Reuploads as the new sender
contract_counter.call_as(&new_sender).upload().unwrap();
// Here the contract_counter sender is again `sender`
// Sets the new_sender as the definite sender
contract_counter.set_sender(&new_sender);
// From now on the contract_counter sender is `new_sender`
Additional customization
As we don’t provide wrappers around each and every functionality that cw-multi-test
provides, you can also customize the underlying cw_multi_test::App
object to your specific needs. In the following example, we create a new validator in the test environment:
mock.app
.borrow_mut()
.init_modules(|router, api, storage| {
router.staking.add_validator(
api,
storage,
&BlockInfo {
height: 16736,
time: Timestamp::from_seconds(13345762376),
chain_id: "juno-1".to_string(),
},
cosmwasm_std::Validator {
address: "new-validator-address".to_string(),
commission: Decimal::from_str("0.5").unwrap(), // Greedy validator
max_commission: Decimal::from_str("1").unwrap(), // Dangerous validator
max_change_rate: Decimal::from_str("1").unwrap(), // Very dangerous validator
},
)
})
.unwrap();