|  | 
|  | 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