mockall::mock! { Response { // Note that the return type for text here is technically different than it is in reqwest, // but mockall allows us to change it slightly so we can actually construct the error later // on in the unit tests. pub fn text(self) -> Result>; } } #[derive(Debug, PartialEq, Eq)] pub struct IpGetError; #[arg_ripper::rip(resp: MockResponse)] pub fn get_ip() -> Result { let resp = reqwest::blocking::Client::new() .get("https://ifconfig.me/ip") .send() .map_err(|_| IpGetError)?; resp.text().map_err(|_| IpGetError) } fn main() { let ip = get_ip().unwrap(); println!("{ip}"); tests::mock_response_happy_path(); tests::mock_response_sad_path(); } // In a real application this would follow the typical unit test pattern, instead of being called // from main mod tests { use super::*; pub fn mock_response_happy_path() { let mut mock_resp = MockResponse::new(); mock_resp .expect_text() .return_once(|| Ok("127.0.0.1".to_owned())); assert_eq!(ripped_get_ip(mock_resp), Ok("127.0.0.1".to_owned())); } pub fn mock_response_sad_path() { let mut mock_resp = MockResponse::new(); mock_resp .expect_text() .return_once(|| Err("This error is expected")?); assert_eq!(ripped_get_ip(mock_resp), Err(IpGetError)); } }