Skip to main content

Custom Tests

In this section, I will give you a test for the cw-ica-controller contract. This test demonstrates how to create a new interchain account, fund it, and then stake some tokens with it. And then we will go over this test file line by line to understand the logic behind it.

Replace the contents of e2e/interchaintestv8/contract_test.go with the following code:

e2e/interchaintestv8/contract_test.go
loading...

You need to run go mod tidy to update the indirect dependencies.

go mod tidy

Organization

The tests are organized into subtests using the s.Run method. This method takes a test name and a test function as arguments. The test function is executed when the test is run.

e2e/interchaintestv8/contract_test.go
loading...

Best Practice: Using `s.Run`

Using the s.Run method to organize your tests into subtests makes it easier to understand the purpose of each test and helps you to identify the failing test quickly.

Notice that each s.Run call is also wrapped by a s.Require().True call. This is because without this, sequential subtests will be executed even if the previous subtest fails. You may abstain from doing this if you want to run the subtests even if one of them fails.

Test Logic

We will do a line-by-line analysis of the test logic.

We first call the underlying test suite's setup method. This is where the chains, relayers, connections, and accounts are initialized.

e2e/interchaintestv8/contract_test.go
loading...

UploadAndInstantiateContracts Subtest

Since contract upload and instantiation logic is inside s.Run, we define variables for the instantiated contracts outside of the s.Run method to use them in the subsequent subtests.

e2e/interchaintestv8/contract_test.go
loading...

Best Practice: Storing Instantiated Contracts

Although here we are storing the instantiated contracts in variables, it is advisable to store them in the ContractTestSuite struct to make them accessible to all test functions. It might also be helpful to move contract upload and instantiation logic to the ContractTestSuite's SetupTest method.

This is what is done in the cw-ica-controller's actual test suite. There are a lot of test functions there, which is also a good reference for writing custom tests.

e2e/interchaintestv8/contract_test.go
loading...

Then we open a subtest to upload and instantiate both the cw-ica-controller and callback-counter contracts. We first upload the callback-counter contract:

e2e/interchaintestv8/contract_test.go
loading...

Then we instantiate the callback-counter contract:

e2e/interchaintestv8/contract_test.go
loading...

Notice that the callback-counter takes no arguments in its instantiation.

Then we upload and instantiate the cw-ica-controller contract:

e2e/interchaintestv8/contract_test.go
loading...

Channel Open Init on Instantiate

Recall that the cw-ica-controller initiates the channel opening handshake upon its instantiation. This is why we wait for 5 blocks after the instantiation to ensure that the handshake is completed.

e2e/interchaintestv8/contract_test.go
loading...

Verify_ChannelOpenHandshake Subtest

The next subtest is a set of assertions to ensure that the interchain account was created successfully:

e2e/interchaintestv8/contract_test.go
loading...

Best Practice: gRPC Query Client

Notice the use of the autogenerated query client for both the cw-ica-controller and callback-counter contracts. This is the recommended way to query the contracts although you can also use the .Query method on the contract instance.

e2e/interchaintestv8/contract_test.go
loading...

Test_CosmosMsg_Delegate Subtest

In the next subtest, we fund the interchain account and stake some tokens with it. We fund the interchain account using the s.FundAddressChainB method, which can be found in e2e/interchaintestv8/e2esuite/utils.go.

e2e/interchaintestv8/contract_test.go
loading...

Next, we construct the execute message to stake tokens with the interchain account:

e2e/interchaintestv8/contract_test.go
loading...

Then we use the contract.Execute method to execute the message, and we wait for 5 blocks to ensure that the IBC packet lifecycle is completed:

e2e/interchaintestv8/contract_test.go
loading...

The rest of the subtest is a set of assertions to ensure that the delegation was successful:

e2e/interchaintestv8/contract_test.go
loading...

Thank you for reading this tutorial. I hope you found it helpful.