如何将模拟实例注入 Rust 特征,同时保留该模拟的引用

问题描述 投票:0回答:1

我制作了这个名为 Oracle 的 Rust 结构,它可以回答任何问题

/// Oracle is a wise entity that can answer questions
pub struct Oracle {
    source: Rc<dyn WisdomSource>,
}

impl Oracle {
    pub fn new() -> Oracle {
        Oracle {
            source: Rc::new(Magic8Ball)
        }
    }

    pub fn ask(&self, question: &String) -> String {
        self.source.ask(question)
    }
}

神谕拥有智慧的源泉,可以用来寻求问题的答案。

/// Trait for a source of wisdom
#[mockall::automock]
trait WisdomSource {
    fn ask(&self, question: &String) -> String;
}

/// Default source of wisdom implementation
struct Magic8Ball;

impl WisdomSource for Magic8Ball {
    fn ask(&self, question: &String) -> String {
        let answers = vec!["yes", "no", "maybe", "ask again later"];

        let mut hasher = DefaultHasher::new();
        question.hash(&mut hasher);
        let hash_value = hasher.finish();
        let index = (hash_value % 4) as usize;
        
        answers[index].to_string()
    }    
}

为了对此预言机进行单元测试,我将注入 WisdomSource 的模型

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

    #[test]
    fn test_sage() {
        let mut mockup_source = MockWisdomSource::new();
        mockup_source.expect_ask().times(1).return_const("42".to_string());
        
        let source: Rc<dyn WisdomSource> = Rc::new(mockup_source);
        
        let sage = Oracle{source};
        let answer = sage.ask(&"What is the meaning of life?".to_string());

        assert_eq!(answer, "42");
        
        // Check that the mockup was called
        mockup_source.checkpoint();  // How to get access get reference to the mockup_source?

    }
}

单元测试的最后一行无法编译,因为“mockup_source”的所有权已转移到 RC“source”。

我无法使用 RC 的引用,因为该特征没有 checkpoint() 方法。

AFAIK,我无法将 '&dyn WisdomSource' 向上转换为 '&MockWisdomSource'

在保留能够使用这些模拟功能的东西的同时注入模拟的正确方法是什么?

rust borrow-checker mockall
1个回答
0
投票

kmdreko 的提示似乎有效。 Oracle 现在拥有 RC

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

impl Oracle {
    pub fn new() -> Oracle {
        Oracle {
            source: Rc::new(RefCell::new(Magic8Ball))
        }
    }

    pub fn ask(&self, question: &String) -> String {
        self.source.borrow_mut().ask(question)
    }
}

然后在单元测试中,我将保留模拟的 RefCell 的 RC,并将该 RC 的克隆注入到 Oracle

#[test]
fn test_sage() {
    let mockup_rc = Rc::new(RefCell::new(MockWisdomSource::new()));
    mockup_rc.borrow_mut().expect_ask().times(1).return_const("42".to_string());

    let source = Rc::clone(&mockup_rc) as Rc<RefCell<dyn WisdomSource>>;        
    let sage = Oracle{source};
    
    let answer = sage.ask(&"What is the meaning of life?".to_string());

    assert_eq!(answer, "42");
    
    // Check that the mockup was called
    mockup_rc.borrow_mut().checkpoint();
}
© www.soinside.com 2019 - 2024. All rights reserved.