Deploying contracts from tests
For most projects, testing of isolated functions won't be enough.
Protostar provides a deploy_contract
cheatcode to test interactions between contracts.
We will use an example of a simple storage contract to show you how to deploy contract inside a test case.
First, inside a src
directory, create a storage_contract.cairo
src/storage_contract.cairo
%lang starknet
from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.uint256 import Uint256, uint256_add
// Define a storage variable.
@storage_var
func balance() -> (res: Uint256) {
}
@storage_var
func id() -> (res: felt) {
}
// Increases the balance by the given amount.
@external
func increase_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
amount: Uint256
) {
let (read_balance) = balance.read();
let (new_balance, carry) = uint256_add(read_balance, amount);
assert carry = 0;
balance.write(new_balance);
return ();
}
// Returns the current balance.
@view
func get_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
res: Uint256
) {
let (res) = balance.read();
return (res,);
}
@view
func get_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (res: felt) {
let (res) = id.read();
return (res,);
}
@constructor
func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
initial_balance: Uint256, _id: felt
) {
balance.write(initial_balance);
id.write(_id);
return ();
}
Then we can create a test case for the contract.
Inside tests
directory, create a test_storage_contract.cairo
file.
tests/test_storage_contract.cairo
%lang starknet
from starkware.cairo.common.uint256 import Uint256
@contract_interface
namespace StorageContract {
func increase_balance(amount: Uint256) {
}
func get_balance() -> (res: Uint256) {
}
func get_id() -> (res: felt) {
}
}
@external
func test_proxy_contract{syscall_ptr: felt*, range_check_ptr}() {
alloc_locals;
local contract_address: felt;
// We deploy contract and put its address into a local variable. Second argument is calldata array
%{ ids.contract_address = deploy_contract("./src/storage_contract.cairo", [100, 0, 1]).contract_address %}
let (res) = StorageContract.get_balance(contract_address=contract_address);
assert res.low = 100;
assert res.high = 0;
let (id) = StorageContract.get_id(contract_address=contract_address);
assert id = 1;
StorageContract.increase_balance(contract_address=contract_address, amount=Uint256(50, 0));
let (res) = StorageContract.get_balance(contract_address=contract_address);
assert res.low = 150;
assert res.high = 0;
return ();
}
info
Please refer to "passing tuples and structs in calldata" on how to serialize your constructor arguments to an array of integers
Then run your test with
protostar test-cairo0 ./tests
expected result
Collected 2 items
storage_test: .
test_utils: .
----- TEST SUMMARY ------
2 passed
Ran 2 out of 2 total tests