Test Authorization
Tests can assert on the auths that are expected to occur.
The following example sets up a test environment, registers an increment contract, and checks after the increment invocation what auths were required.
#[test]
fn test() {
let env = Env::default();
env.mock_all_auths();
let contract_id = env.register(IncrementContract, ());
let client = IncrementContractClient::new(&env, &contract_id);
let user_1 = Address::random(&env);
assert_eq!(client.increment(&user_1, &5), 5);
// Verify that the user indeed had to authorize a call of `increment` with
// the expected arguments:
assert_eq!(
// Get the auths that were seen in the last invocation.
env.auths(),
std::vec![(
// Address for which authorization check is performed
user_1.clone(),
// Invocation tree that needs to be authorized
AuthorizedInvocation {
// Function that is authorized. Can be a contract function or
// a host function that requires authorization.
function: AuthorizedFunction::Contract((
// Address of the called contract
contract_id.clone(),
// Name of the called function
symbol_short!("increment"),
// Arguments used to call `increment` (converted to the
// env-managed vector via `into_val`)
(user_1.clone(), 5_u32).into_val(&env),
)),
// The contract doesn't call any other contracts that require
// authorization,
sub_invocations: std::vec![]
}
)]
);
}
For the full example the above snippet is extracted from, see the auth example contract.
Testing Constructor Authorization
Env::register and Env::register_at invoke a contract's constructor with authorization mocked: the environment switches to recording auth for the constructor call, so any require_auth calls the constructor makes are automatically authorized regardless of the environment's authorization mode. Because of this, registering a contract cannot be used to test its constructor's authorization.
To test a constructor's authorization, deploy the contract the way it is deployed on-chain, using the deployer returned by env.deployer(), e.g. with_address followed by deploy_v2. Deploying that way runs the constructor subject to the environment's authorization, so require_auth in the constructor behaves as it would on-chain and can be tested the same way as any other authorized call.
See the deployer example contract for a full example of using env.deployer().
Guides in this category:
Unit Tests
Unit tests are small tests that test smart contracts.
Mocking
Mocking dependency contracts in tests.
Test Authorization
Write tests that test contract authorization.
Test Events
Write tests that test contract events.
Integration Tests
Integration testing uses dependency contracts instead of mocks.
Fork Testing
Integration testing using mainnet data.
Fuzzing
Fuzzing and property testing to find unexpected behavior.
Differential Tests
Differential testing detects unintended changes.
Differential Tests with Test Snapshots
Differential testing using automatic test snapshots.
Mutation Testing
Mutation testing finds code not tested.
Code Coverage
Code coverage tools find code not tested.
Testing with Ledger Snapshot
Use ledger snapshots to test contracts with ledger data