如何使用Rust trait抽象HTTP调用以支持代码测试?
问题根因
你误用了std::marker::Send,这个是Rust的自动标记trait,作用仅仅是标识类型可以安全跨线程转移所有权,本身不定义任何方法,和Go里用来约定方法集合的接口完全不是一类东西,编译器自然找不到send()方法。
正确实现
你想的没错,确实需要自定义trait来完成HTTP调用的抽象,思路和Go里定义接口约束入参的逻辑完全一致,区别只是Rust需要你显式声明trait包含的方法签名,参考实现如下:
use serde_json::Value; use std::error::Error; // 抽象HTTP客户端能力,对应你需要的send方法 trait HttpClient { type Resp: HttpResponse; type Err: Error; async fn send(self) -> Result<Self::Resp, Self::Err>; } // 抽象HTTP响应能力,对应你需要的text方法 trait HttpResponse { type Err: Error; async fn text(self) -> Result<String, Self::Err>; } // 业务逻辑基于trait编写,和Go传接口的可测试性效果完全一致 async fn get_servers<C: HttpClient>(client: C) -> Result<String, Box<dyn Error>> { let resp = client.send().await?; let servers_str = resp.text().await?; let v: Value = serde_json::from_str(&servers_str)?; println!("{:?}", v); Ok(servers_str) }
针对生产环境用的真实HTTP客户端(比如reqwest的RequestBuilder),你只要给它补上对应trait的impl即可;写单元测试时不需要发起真实网络请求,自定义Mock类型实现这两个trait,返回预设的测试响应文本就行,和Go里写Mock结构体实现接口的测试逻辑没有本质区别。
如果你的项目里HTTP调用逻辑比较简单,自己按需定义这两个轻量trait就足够用,不需要引入额外的Mock库或者复杂抽象。
内容的提问来源于stack exchange,提问作者Justin Thomas
相关产品推荐
相关产品推荐

