Tests
Debugging contracts explains that it is much more convenient to debug using native code than Wasm. Given that you are testing native code, it is tempting to interact with your contract directly using function calls. If you attempt this approach, you will find that it doesn't always work. Function call interactions do not set the environment into the correct state for contract execution, so functions involving contract data and determining the current or invoking contract will not work.
When writing tests, it is important to always interact with contracts through contract invocation. In a production setting, contract invocation will execute Wasm bytecode loaded from the ledger. So how does this work if you are testing native code? You must register your contract with the environment, so it knows what functions are available and how to call them. While this sounds complex, the contractimpl
procedural macro automatically generates almost all the code to do this. All you have to do is write a small stub to actually call the generated code, such as
pub fn register_test_contract(e: &Env, contract_id: &[u8; 32]) {
let contract_id = FixedBinary::from_array(e, *contract_id);
e.register_contract(&contract_id, crate::contract::Token {});
}
Some contracts, such as the token contract, also provide a friendlier interface to facilitate testing. There are many ways these interfaces might make testing easier, but one common one is to allow automatic message signing by passing a ed25519_dalek::Keypair.
Note that everything described in this section is only available if the testutils
feature is enabled.
Example
This machinery can also be used to test multiple contracts together. For example, the single offer contract test case creates a token.