Rust嵌套Mock方法预期设置报错及解决方案
问题描述
尝试Mock一个返回另一个Mock对象的trait方法时失败,出现错误:
no method named `returning` found for mutable reference `&mut __get_account_query::Expectation` in the current scope method not found in `&mut Expectation`
处理程序代码
pub struct AppState { db: Box<dyn QueryDependency>, } #[post("/create")] pub async fn create_account( data: web::Data<AppState> ) -> impl Responder { ..... ..... let result = data.db.get_account_query().create_account(&new_account).await; // 尝试Mock的函数 } #[actix_web::test] async fn create_account_test() { let mock_db = MockQueryDependency::new(); let mut mock_account_query = MockAccountQuery::new(); mock_account_query .expect_create_account() .times(1) .returning(|_| Ok(Account { id: 1, name: "test".to_string(), })); mock_db.expect_get_account_query().times(1).returning(|| &mock_account_query); let mock_state = AppState { db: Box::new(mock_db), }; }
Trait定义
#[cfg(test)] use mockall::automock; #[cfg_attr(test, automock)] pub trait QueryDependency: Send + Sync { fn get_account_query(&self) -> &dyn AccountQuery; } #[cfg_attr(test, automock)] #[async_trait] pub trait AccountQuery: Send + Sync { async fn create_account(&self, new_account: &NewAccount) -> Result<Account, sqlx::Error>; }
解决方法
核心问题
错误源于QueryDependency的get_account_query方法返回引用类型,直接返回局部MockAccountQuery实例的引用会触发生命周期不匹配,同时mockall对返回引用的方法的Expectation类型不支持直接使用returning方法。
具体修复步骤
- 用
Arc共享Mock实例:通过Arc包裹MockAccountQuery,确保引用生命周期与MockQueryDependency匹配,避免所有权问题。 - 调整mock返回逻辑:使用
move闭包配合Arc::as_ref返回符合要求的引用。
修改后的测试代码:
use std::sync::Arc; #[actix_web::test] async fn create_account_test() { // 用Arc包裹MockAccountQuery,实现共享所有权 let mock_account_query = Arc::new(MockAccountQuery::new()); // 克隆Arc用于设置create_account的期望(原Arc会被move到闭包中) let mut mock_account_query_clone = Arc::clone(&mock_account_query); // 设置create_account的调用期望 mock_account_query_clone .expect_create_account() .times(1) .returning(|_| Ok(Account { id: 1, name: "test".to_string(), })); let mut mock_db = MockQueryDependency::new(); // 设置get_account_query的返回,用move闭包返回Arc的引用 mock_db.expect_get_account_query() .times(1) .returning(move || Arc::as_ref(&mock_account_query)); let mock_state = AppState { db: Box::new(mock_db), }; // 此处可添加发送请求并验证结果的代码 }
额外说明
- 如果允许修改原trait,可将
get_account_query的返回类型改为Arc<dyn AccountQuery>,这样mock时无需处理引用,直接返回Arc实例即可,代码会更简洁。 - 确保使用较新版本的mockall,旧版本对返回引用的方法支持可能存在缺陷。
内容的提问来源于stack exchange,提问作者Jackal
相关产品推荐
相关产品推荐

