testing
Testing Your Module
Integration Testing
Integration testing your contract with the account contracts involves deploying your contract and any of its dependencies to a mock bitsong environment, and any other environment where you want to test actions with. To make this as easy as possible, an abstract-client
package is available that you can use to deploy on any of your modules to a mock environment. We will cover this client in the next section.
Local Daemon Testing
Once you have confirmed that your module works as expected you can spin up a local node and deploy A2B + your app onto the chain. You can do this by running the local_daemon
example, which uses a locally running Bitsong daemon to deploy to. At this point you can also test your front-end with the contracts.
Unit-testing
The lowest level of testing is unit testing. Unit tests allow you to easily test complex, self-contained logic. Because unit tests should be self-contained, any queries made to other contracts need to be mocked. These mocks act as “query catchers”, allowing you to specify a response for a specific query.
Sadly constructing these mock queries is time-consuming and involves a lot of boilerplate. Additionally, there are queries that your module should always support as they are part of its base implementation. For those reasons we created an abstract-testing
package.
The abstract-testing
provides you with some small abstractions that allow you to mock Smart and Raw queries with ease.
Mock Querier
The abstract-testing package contains a MockQuerierBuilder. It uses the common builder pattern to allow for efficient mock construction. Let’s see how!
Mocking Raw Queries
Instead of manually mapping the key-value relation and it’s types, we can use the available contract storage types. Using the storage types ensures that the mock and its data operations are the same as in the actual implementation. It also saves us a lot of work related to key serialization.
Items and Maps
The MockQuerierBuilder also provides a with_items
and with_maps
function. These functions allow you to easily mock Item
and Map
datastores.
This approach allow you to easily map Item
and Map
datastores.
let contract_address = api.addr_make("bitsong1...");
let querier = MockQuerierBuilder::default()
.with_raw_handler(&contract_address, |key: &str| {
// Example: Let's say, in the raw storage, the key "KEY" maps to the value "VALUE"
match key {
"KEY" => to_json_binary("VALUE").map_err(|e| e.to_string()),
_ => to_json_binary("").map_err(|e| e.to_string()),
}
})
.build();
Abstract Querier
The easiest and best way to start using the querier is to use the AbstractMockQuerierBuilder::mocked_account_querier_builder()
method. This method sets up a mock querier with an initial Bitsong Abstract Account.
IBC Application Testing
One of the hardest steps in building an interchain application is testing. Due to the complexity of IBC and Cosmos SDK chains there are some trade-offs to consider in your approach to testing.
Testing Tools
This section aims to provide you with a high-level overview of the available testing tools and how to use them. That way you can make an informed decision on which tool is best for your application’s needs.
Mock IBC Testing
he easiest way to test your CosmWasm IBC application is by using cw-orchestrator’s mock IBC environment. This testing environment allows you to connect multiple Mock
instances over a virtual IBC connection. Relaying is simulated and you can test your application’s IBC logic without needing to deploy it to a live chain.
Type: MockBech32Interchain
Advantages:
Easy to set up and use.
Very fast to execute.
Easily configurable.
Disadvantages:
Does not support custom Cosmos SDK modules.
Not end-to-end.
Can’t make use of existing on-chain infrastructure.
Starship
Starship is a kubernetes-based Cosmos SDK environment spawner. It allows you to spin up multiple Cosmos SDK blockchain networks and connect them together. It includes a relayer, faucet and block explorer. Allowing you to test your application in a more realistic environment.
Type: Starship
Advantages:
Access to Cosmos SDK modules from your smart contract.
End-to-end testing.
Can be made available for front-end testing.
Disadvantages:
Slow to execute.
Requires more setup and knowledge to use.
Can only run for limited time due to resource constraints.
Testnet
The final option is to deploy your application to a testnet. Doing this will ensure your application is tested in a real-world environment and makes it possible to start sharing what you’ve built with others. However, this approach is the most time-consuming and requires the most setup.
Advantages:
Real-world testing.
Can be shared with others.
Can be used for marketing purposes.
Disadvantages:
Slow to execute.
Requires running your own relayer (or partnering with a relayer service).
Testnets are often unstable.
Testing Bitsong Apps
Local & Mock Environments
For local and mock environments, the AbstractInterchainClient::deploy_on
function exists. This function can take a MockBech32Interchain
or Starship
argument and it will deploy the Bitsong Abstract contracts to the environment and set up the necessary IBC connections.
let interchain = MockBech32InterchainEnv::new(
vec![("bobnet-1", "bitsong"), ("uni-5", "juno")],
);
let abstract_interchain = AbstractInterchainClient::deploy_on(&interchain);
// single-chain client
let bitsong_abstract: AbstractClient = abstract_interchain.client("bobnet-1");
Testnet/Mainnet Environments
Abstract maintains deployments for a few testnets and for most mainnets, as well as Bitsong. Instead of re-deploying Bitsong Abstract to these networks you can make use of the load_from
function on AbstractInterchainClient
. To do this, first construct an InterchainDaemon
object with the chains you’d like to use.
let interchain = DaemonInterchain::new(vec![
(LOCAL_JUNO, None),
(LOCAL_BITSONG, None)
], &ChannelCreationValidator)?;
let abstract_interchain = AbstractInterchainClient::load_from(&interchain);
// single-chain client
let bitsong_abstract: AbstractClient = abstract_interchain.client("bobnet-1");
Last updated