use reqwest::ClientBuilder; use std::error::Error; struct DynDnsService {} impl DynDnsService { pub async fn register(config: &impl DynDnsServiceConfiguration) -> Result<(), Box> { let client = ClientBuilder::new().build()?; client.post(config.get_service_url()).send().await?; Ok(()) } } trait DynDnsServiceConfiguration { fn get_service_url(&self) -> String; } #[cfg(test)] mod tests { use super::*; use std::error::Error; use wiremock::matchers::{method, path}; use wiremock::{Mock, MockServer, ResponseTemplate}; async fn setup_dyndns_service(service_path: &str) -> MockServer { let service = MockServer::start().await; Mock::given(method("POST")) .and(path(service_path)) .respond_with(ResponseTemplate::new(200)) .mount(&service) .await; service } #[tokio::test] async fn successful_dyndns_registration() -> Result<(), Box> { let service_path = "register-my-ip-address"; let dyndns_service = setup_dyndns_service(service_path).await; let service_config = TestDynDnsServiceConfiguration::new(&dyndns_service, service_path); DynDnsService::register(&service_config).await?; assert_eq!(1, dyndns_service.received_requests().await.unwrap().len()); Ok(()) } struct TestDynDnsServiceConfiguration { service_path: String, } impl TestDynDnsServiceConfiguration { fn new(server: &MockServer, path: &str) -> Self { Self { service_path: format!("{}/{}", server.uri(), path), } } } impl DynDnsServiceConfiguration for TestDynDnsServiceConfiguration { fn get_service_url(&self) -> String { self.service_path.clone() } } }