Skip to content

Commit 839df3b

Browse files
committed
Added MultiTest intro for testing query.
1 parent 46433b7 commit 839df3b

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
---
2+
sidebar_position: 6
3+
---
4+
5+
# Introducing MultiTest
6+
7+
Let's introduce [MultiTest], a library for testing smart contracts in Rust.
8+
9+
The core idea of [MultiTest] is to abstract smart contracts and simulate the blockchain
10+
environment for testing purposes. The purpose of this is to be able to test communication between smart contracts.
11+
It does its job well, ant it is also an excellent tool for testing single-contract scenarios.
12+
13+
First, we need to add [MultiTest] dependency to our `Cargo.toml`.
14+
15+
```toml title="Cargo.toml"
16+
[package]
17+
name = "contract"
18+
version = "0.1.0"
19+
edition = "2021"
20+
21+
[lib]
22+
crate-type = ["cdylib"]
23+
24+
[dependencies]
25+
cosmwasm-std = { version = "3", features = ["staking"] }
26+
serde = { version = "1.0.214", default-features = false, features = ["derive"] }
27+
28+
[dev-dependencies]
29+
cw-multi-test = "3"
30+
```
31+
32+
We have added a new
33+
[`[dev-dependencies]`](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies)
34+
section with dependencies not used by the final binary but which may be used by tools around the
35+
development process - for example, tests.
36+
37+
Once the dependency is there, let's update our test to use the framework:
38+
39+
```rust title="src/contract.rs" {23-25,39-76}
40+
use crate::msg::{GreetResp, QueryMsg};
41+
use cosmwasm_std::{
42+
to_json_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdResult,
43+
};
44+
45+
pub fn instantiate(
46+
_deps: DepsMut,
47+
_env: Env,
48+
_info: MessageInfo,
49+
_msg: Empty,
50+
) -> StdResult<Response> {
51+
Ok(Response::new())
52+
}
53+
54+
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
55+
use QueryMsg::*;
56+
57+
match msg {
58+
Greet {} => to_json_binary(&query::greet()?),
59+
}
60+
}
61+
62+
pub fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult<Response> {
63+
unimplemented!()
64+
}
65+
66+
mod query {
67+
use super::*;
68+
69+
pub fn greet() -> StdResult<GreetResp> {
70+
let resp = GreetResp {
71+
message: "Hello World".to_owned(),
72+
};
73+
74+
Ok(resp)
75+
}
76+
}
77+
78+
#[cfg(test)]
79+
mod tests {
80+
use cosmwasm_std::Addr;
81+
use cw_multi_test::{App, ContractWrapper, Executor};
82+
83+
use super::*;
84+
85+
#[test]
86+
fn greet_query() {
87+
let mut app = App::default();
88+
89+
let code = ContractWrapper::new(execute, instantiate, query);
90+
let code_id = app.store_code(Box::new(code));
91+
92+
let addr = app
93+
.instantiate_contract(
94+
code_id,
95+
Addr::unchecked("owner"),
96+
&Empty {},
97+
&[],
98+
"Contract",
99+
None,
100+
)
101+
.unwrap();
102+
103+
let resp: GreetResp = app
104+
.wrap()
105+
.query_wasm_smart(addr, &QueryMsg::Greet {})
106+
.unwrap();
107+
108+
assert_eq!(
109+
resp,
110+
GreetResp {
111+
message: "Hello World".to_owned()
112+
}
113+
);
114+
}
115+
}
116+
```
117+
118+
You've probably noticed that we have added the function for an `execute` entry point. We didn't add the
119+
entrypoint itself or the function's implementation, but for multitest purposes, the contract has to
120+
contain at least instantiate, query, and execute handlers. We attributed the function as
121+
[`#[allow(dead_code)]`](https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes),
122+
so, `cargo` will not complain about it not being used anywhere. Enabling it for tests only with
123+
`#[cfg(test)]` would also be a way.
124+
125+
Then, at the beginning of the test, we created the
126+
[`App`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#) object. It is a core
127+
multitest entity representing the virtual blockchain on which we will run our contracts. As you can
128+
see, we can call functions on it just like we could when interacting with a blockchain using
129+
`wasmd`!
130+
131+
Right after creating `app`, we prepared the representation of the `code`, which would be "uploaded"
132+
to the blockchain. As _multi-tests_ are just native Rust tests, they do not involve any Wasm binaries,
133+
but this name matches well what happens in a real-life scenario. We store this object in the
134+
blockchain with the
135+
[`store_code`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.store_code)
136+
function, and as a result, we are getting the code id, we would need it to instantiate a contract.
137+
138+
Instantiation is the next step. In a single
139+
[`instantiate_contract`](https://docs.rs/cw-multi-test/latest/cw_multi_test/trait.Executor.html#method.instantiate_contract)
140+
call, we provide everything we would provide via `wasmd` - the contract code id, the address which
141+
performs instantiation,
142+
143+
the message triggering it, and any funds sent with the message (again - empty for now). We are
144+
adding the contract label and its admin for migrations - `None`, as we don't need it yet.
145+
146+
And after the contract is online, we can query it. The
147+
[`wrap`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html?search=in#method.wrap)
148+
function is an accessor for querying Api (queries are handled a bit differently than other calls),
149+
and the
150+
[`query_wasm_smart`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.QuerierWrapper.html#method.query_wasm_smart)
151+
queries are given a contract with the message. Also, we don't need to care about query results as
152+
`Binary` - multitest assumes that we would like to deserialize them to some response type, so it
153+
takes advantage of Rust type elision to provide us with a nice Api.
154+
155+
Now it's time to rerun the test. It should still pass, but now we nicely abstracted the testing
156+
contract as a whole, not some internal functions. The next thing we should probably cover is making
157+
the contract more interesting by adding some state.
158+
159+
[MultiTest]: ../../multi-test/introduction.md

0 commit comments

Comments
 (0)