You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在注入Rust trait Mock实例时保留其引用以调用Mock方法

解决方案

针对你遇到的问题,这里有三种实用的解决思路:

1. 将Mock专属方法整合到Trait中

如果checkpoint()是WisdomSource这个抽象应该具备的能力(比如测试场景下的通用操作),直接把它加入trait定义。mockall会自动为生成的Mock实现这个方法,这样即使包装成Rc<dyn WisdomSource>,也能直接调用该方法。

示例代码:

use mockall::mock;
use std::rc::Rc;

// 定义包含checkpoint的Trait
trait WisdomSource {
    fn get_answer(&self) -> String;
    fn checkpoint(&self); // 新增方法
}

// 生成Mock实现
mock! {
    pub WisdomSource {}
    impl WisdomSource for WisdomSource {
        fn get_answer(&self) -> String;
        fn checkpoint(&self);
    }
}

struct Oracle {
    source: Rc<dyn WisdomSource>,
}

impl Oracle {
    fn new(source: Rc<dyn WisdomSource>) -> Self {
        Oracle { source }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_oracle() {
        let mut mock = MockWisdomSource::new();
        mock.expect_get_answer().returning(|| "test answer".to_string());
        mock.expect_checkpoint().once();

        let oracle = Oracle::new(Rc::new(mock) as Rc<dyn WisdomSource>);
        assert_eq!(oracle.source.get_answer(), "test answer");
        oracle.source.checkpoint(); // 直接调用
    }
}

2. 利用Rc的向下转型能力

mockall生成的Mock类型自动实现了Any trait,因此可以通过Rc::downcast将Rc<dyn WisdomSource>转回具体的Rc<MockWisdomSource>,从而调用专属方法。

示例代码:

use mockall::mock;
use std::any::Any;
use std::rc::Rc;

// 让Trait继承Any,支持向下转型
trait WisdomSource: Any {
    fn get_answer(&self) -> String;
}

mock! {
    pub WisdomSource {}
    impl WisdomSource for WisdomSource {
        fn get_answer(&self) -> String;
    }
}

struct Oracle {
    source: Rc<dyn WisdomSource>,
}

impl Oracle {
    fn new(source: Rc<dyn WisdomSource>) -> Self {
        Oracle { source }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_oracle() {
        let mut mock = MockWisdomSource::new();
        mock.expect_get_answer().returning(|| "test answer".to_string());

        let rc_mock = Rc::new(mock) as Rc<dyn WisdomSource>;
        let oracle = Oracle::new(Rc::clone(&rc_mock));

        // 向下转型到具体Mock类型,失败时会panic,测试环境可接受
        let mock_ref = rc_mock.downcast::<MockWisdomSource>().unwrap();
        mock_ref.checkpoint(); // 调用Mock专属方法

        assert_eq!(oracle.source.get_answer(), "test answer");
    }
}

3. 单独持有Mock实例的引用

在测试代码中,同时保留原始Mock实例的Rc引用,将克隆后的Rc包装成trait对象注入Oracle。这样无需转型,直接用原始引用调用Mock专属方法。

示例代码:

use mockall::mock;
use std::rc::Rc;

trait WisdomSource {
    fn get_answer(&self) -> String;
}

mock! {
    pub WisdomSource {}
    impl WisdomSource for WisdomSource {
        fn get_answer(&self) -> String;
    }
}

struct Oracle {
    source: Rc<dyn WisdomSource>,
}

impl Oracle {
    fn new(source: Rc<dyn WisdomSource>) -> Self {
        Oracle { source }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_oracle() {
        let mut mock = MockWisdomSource::new();
        mock.expect_get_answer().returning(|| "test answer".to_string());

        let rc_mock = Rc::new(mock);
        // 克隆Rc注入Oracle,保留原始rc_mock的所有权
        let oracle = Oracle::new(Rc::clone(&rc_mock) as Rc<dyn WisdomSource>);

        rc_mock.checkpoint(); // 直接调用Mock专属方法
        assert_eq!(oracle.source.get_answer(), "test answer");
    }
}

这种方式最简单直接,适合不需要在Oracle内部触发checkpoint,仅在测试逻辑中手动调用的场景。

内容的提问来源于stack exchange,提问作者Heikki Taavettila

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 18:40:12