Effect Mocking
Because effects are explicit in Fe, testing functions that use effects is straightforward: provide the effect with a with expression.
Mocking with with
Section titled “Mocking with with”For a function that declares an application-owned effect type, provide a value of that type:
struct Config { max_transfer: u256, fee_rate: u256,}
fn calculate_fee(amount: u256) -> u256 uses (config: Config) { amount * config.fee_rate / 10000}
fn is_within_limit(amount: u256) -> bool uses (config: Config) { amount <= config.max_transfer}
#[test]fn test_fee_calculation() { let config = Config { max_transfer: 1000, fee_rate: 250 }
let fee = with (config) { calculate_fee(amount: 400) } assert!(fee == 10) // 400 * 250 / 10000 = 10}
#[test]fn test_transfer_limit() { let config = Config { max_transfer: 1000, fee_rate: 250 }
let ok = with (config) { is_within_limit(amount: 500) } assert!(ok == true)
let too_much = with (config) { is_within_limit(amount: 2000) } assert!(too_much == false)}No mocking framework needed. The effect is just a struct — you create it with whatever values your test needs.
Testing with Different Configurations
Section titled “Testing with Different Configurations”Test the same function under different conditions by providing different effect values:
#[test]fn test_fee_rates() { // No fee let zero_fee = Config { max_transfer: 1000, fee_rate: 0 } let fee = with (zero_fee) { calculate_fee(amount: 1000) } assert!(fee == 0)
// 1% fee let low_fee = Config { max_transfer: 1000, fee_rate: 100 } let fee = with (low_fee) { calculate_fee(amount: 1000) } assert!(fee == 10)
// 5% fee let high_fee = Config { max_transfer: 1000, fee_rate: 500 } let fee = with (high_fee) { calculate_fee(amount: 1000) } assert!(fee == 50)}Testing Mutable Effects
Section titled “Testing Mutable Effects”For functions that modify effects, use mut bindings:
struct Counter { value: u256, limit: u256,}
fn increment() -> bool uses (counter: mut Counter) { if counter.value >= counter.limit { return false } counter.value += 1 true}
fn current() -> u256 uses (counter: Counter) { counter.value}
#[test]fn test_increment_with_limit() { let mut counter = Counter { value: 0, limit: 2 }
with (mut counter) { // Below the limit — increments succeed assert!(increment() == true) assert!(current() == 1)
assert!(increment() == true) assert!(current() == 2)
// At limit — increment is rejected, value unchanged assert!(increment() == false) assert!(current() == 2) }}Why This Works
Section titled “Why This Works”In languages without explicit effects, mocking requires frameworks, dependency injection containers, or monkey-patching. In Fe, effects are already explicit in the function signature — so “mocking” is just providing a value. There is no hidden state to intercept.
Standard EVM capability traits such as Ctx, Call, and Log are sealed and cannot be implemented by arbitrary application mocks. Use Evm for integration tests, or put business logic behind your own effect type or trait for unit testing.