mock_call
Cheatcodes mocking contract entry point calls:
mock_call
fn mock_call<T, impl TSerde: serde::Serde<T>, impl TDestruct: Destruct<T>>( contract_address: ContractAddress, function_selector: felt252, ret_data: T, n_times: u32 )
Mocks contract call to a function_selector
of a contract at the given address, for n_times
first calls that are made to the contract.
A call to function function_selector
will return data provided in ret_data
argument.
An address with no contract can be mocked as well.
An entrypoint that is not present on the deployed contract is also possible to mock.
Note that the function is not meant for mocking internal calls - it works only for contract entry points.
start_mock_call
fn start_mock_call<T, impl TSerde: serde::Serde<T>, impl TDestruct: Destruct<T>>( contract_address: ContractAddress, function_selector: felt252, ret_data: T )
Mocks contract call to a function_selector
of a contract at the given address, indefinitely.
See mock_call
for comprehensive definition of how it can be used.
stop_mock_call
fn stop_mock_call(contract_address: ContractAddress, function_selector: felt252)
Cancels the mock_call
/ start_mock_call
for the function function_selector
of a contract at the given address.
Example
Let's consider a contract which simulates a shopping cart. It has a function get_products
that returns a list of products in the cart.
#[derive(Copy, Debug, Drop, Serde, starknet::Store)]
pub struct Product {
pub name: felt252,
pub price: u64,
pub quantity: u64,
}
#[starknet::interface]
pub trait IShoppingCart<TContractState> {
fn get_products(self: @TContractState) -> Array<Product>;
}
#[starknet::contract]
pub mod ShoppingCart {
use starknet::storage::{MutableVecTrait, StoragePointerReadAccess, Vec, VecTrait};
use super::Product;
#[storage]
struct Storage {
products: Vec<Product>,
}
#[constructor]
fn constructor(ref self: ContractState, initial_products: Array<Product>) {
for product in initial_products {
self.products.push(product);
}
}
#[abi(embed_v0)]
impl ShoppingCartImpl of super::IShoppingCart<ContractState> {
fn get_products(self: @ContractState) -> Array<Product> {
let mut products = array![];
for i in 0..self.products.len() {
products.append(self.products.at(i).read());
}
products
}
}
}
Test code:
use cheatcodes_reference::mock_call_example::{
IShoppingCartDispatcher, IShoppingCartDispatcherTrait, Product,
};
use snforge_std::{ContractClassTrait, DeclareResultTrait, declare, start_mock_call, stop_mock_call};
#[test]
fn test_mock_call() {
// 1. Create calldata for the contract deployment
let mut calldata = ArrayTrait::new();
// 2. Serialize initial products (in this case an empty array)
let initial_products: Array<Product> = array![];
initial_products.serialize(ref calldata);
// 3. Declare and deploy the ShoppingCart contract
let contract = declare("ShoppingCart").unwrap().contract_class();
let (contract_address, _) = contract.deploy(@calldata).unwrap();
// 4. Create an instance of the dispatcher
let dispatcher = IShoppingCartDispatcher { contract_address };
// 5. Mock the returned value of the `get_products` function
let mock_products = array![
Product { name: 'Banana', price: 2, quantity: 5 },
Product { name: 'Apple', price: 3, quantity: 10 },
];
// 6. Start the mock call with the mocked products
start_mock_call(contract_address, selector!("get_products"), mock_products);
// 7. Call the `get_products` function through the dispatcher
let retrieved_products: Array<Product> = dispatcher.get_products();
// 8. Verify the retrieved products
let product_0 = retrieved_products.at(0);
assert(*product_0.name == 'Banana', 'product_0.name');
assert(*product_0.price == 2, 'product_0.price');
assert(*product_0.quantity == 5, 'product_0.quantity');
let product_1 = retrieved_products.at(1);
assert(*product_1.name == 'Apple', 'product_1.name');
assert(*product_1.price == 3, 'product_1.price');
assert(*product_1.quantity == 10, 'product_1.quantity');
// 9. Stop the mock call
stop_mock_call(contract_address, selector!("get_products"));
}
Let's run the test:
$ snforge test test_mock_call
Output:
Collected 1 test(s) from cheatcodes_reference package
Running 0 test(s) from src/
Running 1 test(s) from tests/
[PASS] cheatcodes_reference_integrationtest::test_mock_call::test_mock_call ([..])
Tests: 1 passed, 0 failed, 0 ignored, [..] filtered out