82 lines
2.6 KiB
Rust
82 lines
2.6 KiB
Rust
//! `MockProvider` is a mock Ethereum provider that can be used for testing purposes.
|
|
//! It allows to simulate Ethereum state and behavior, by explicitly instructing
|
|
//! provider's responses on client requests.
|
|
//!
|
|
//! This can be useful for testing code that relies on providers without the need to
|
|
//! connect to a real network or spend real Ether. It also allows to test code in a
|
|
//! deterministic manner, as you can control the state and behavior of the provider.
|
|
//!
|
|
//! In these examples we use the common Arrange, Act, Assert (AAA) test approach.
|
|
//! It is a useful pattern for well-structured, understandable and maintainable tests.
|
|
|
|
use ethers::prelude::*;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> eyre::Result<()> {
|
|
mocked_block_number().await?;
|
|
mocked_provider_dependency().await?;
|
|
Ok(())
|
|
}
|
|
|
|
async fn mocked_block_number() -> eyre::Result<()> {
|
|
// Arrange
|
|
let mock = MockProvider::new();
|
|
let block_num_1 = U64::from(1);
|
|
let block_num_2 = U64::from(2);
|
|
let block_num_3 = U64::from(3);
|
|
// Mock responses are organized in a stack (LIFO)
|
|
mock.push(block_num_1)?;
|
|
mock.push(block_num_2)?;
|
|
mock.push(block_num_3)?;
|
|
|
|
// Act
|
|
let ret_block_3: U64 = JsonRpcClient::request(&mock, "eth_blockNumber", ()).await?;
|
|
let ret_block_2: U64 = JsonRpcClient::request(&mock, "eth_blockNumber", ()).await?;
|
|
let ret_block_1: U64 = JsonRpcClient::request(&mock, "eth_blockNumber", ()).await?;
|
|
|
|
// Assert
|
|
assert_eq!(block_num_1, ret_block_1);
|
|
assert_eq!(block_num_2, ret_block_2);
|
|
assert_eq!(block_num_3, ret_block_3);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Here we test the `OddBlockOracle` struct (defined below) that relies
|
|
/// on a Provider to perform some logics.
|
|
/// The Provider reference is expressed with trait bounds, enforcing lose coupling,
|
|
/// maintainability and testability.
|
|
async fn mocked_provider_dependency() -> eyre::Result<()> {
|
|
// Arrange
|
|
let (provider, mock) = crate::Provider::mocked();
|
|
mock.push(U64::from(2))?;
|
|
|
|
// Act
|
|
// Let's mock the provider dependency (we ❤️ DI!) then ask for the answer
|
|
let oracle = OddBlockOracle::new(provider);
|
|
let answer: bool = oracle.is_odd_block().await?;
|
|
|
|
// Assert
|
|
assert!(answer);
|
|
Ok(())
|
|
}
|
|
|
|
struct OddBlockOracle<P> {
|
|
provider: Provider<P>,
|
|
}
|
|
|
|
impl<P> OddBlockOracle<P>
|
|
where
|
|
P: JsonRpcClient,
|
|
{
|
|
fn new(provider: Provider<P>) -> Self {
|
|
Self { provider }
|
|
}
|
|
|
|
/// We want to test this!
|
|
async fn is_odd_block(&self) -> eyre::Result<bool> {
|
|
let block: U64 = self.provider.get_block_number().await?;
|
|
Ok(block % 2 == U64::zero())
|
|
}
|
|
}
|