这看起来非常简单。我希望有一个重复的,但我已经搜索过了。
我正在尝试进行一个测试,调用框架的方法会导致在属于该框架的
parse
中的所有 TextDocument
实现对象上调用方法 HashMap<String, Box<dyn TextDocument>>
。 TextDocument
是一种特质。
所以希望这能让我实现一个像这样的简单的模拟设置:
#[test]
fn each_text_document_is_parsed_in_framework_create_index() -> Result<()>{
let mut docs_parsed = 0;
let increment_count = ||{
docs_parsed += 1
};
struct MockTextDocument {
pub framework: Weak<Framework>,
}
impl TextDocument for MockTextDocument {
fn parse(&self) -> Result<()> {
increment_count();
Ok(())
}
}
...然后我调用框架的方法来引起这个解析,最后进行测试:
framework.create_index();
assert_eq!(docs_parsed, 3);
但这行不通。我从编译器得到这个:
Compiling populate_index_module v0.1.0 (D:\My documents\software projects\workspace\doc_indexer\src\core\populate_index_module)
error[E0434]: can't capture dynamic environment in a fn item
--> tests\test_1.rs:158:4
|
158 | increment_count();
| ^^^^^^^^^^^^^^^
|
= help: use the `|| { ... }` closure form instead
我显然是想在这里使用闭包。但显然这不是正确的方法。
顺便说一句,我不能使用可能属于
parsed: bool
的属性(例如 MockTextDocument
),因为由于不可避免的原因,框架是一个 Rc<Framework>
,所以地图中的所有 Box<dyn TextDocument>
值是“共享引用后面”并且无法访问......换句话说,我相信我必须使用外部计数器变量。
在我的特定情况下,一个额外的复杂性是
MockTextDocument
不能即时创建:它只能在函数内部创建(函数本身就是Framework::new
的参数)。不过,我正在跟进 Vallentin 所说的……
事实上,我认为这是不可能的......所以我想我必须拼凑出另一种不太优雅的方法,比如模拟对象中的
parse
打印“解析...”到stdout
,然后我可以监控其中的内容。
更多详情(Chayim Friedman)
这就是在测试中创建
Framework
期间创建模拟文档的方式:
fn gather_mock_documents(walker: WalkDir, this: &Weak<Framework>) -> HashMap<String, Box<dyn TextDocument>> {
let mut map: HashMap<String, Box<dyn TextDocument>> = HashMap::new();
for i in 0..3 {
let mock_td = MockTextDocument {
framework: this.clone(),
// it seems to me that any closure used here would
// have the same problem: no access to the stack variable
};
map.insert(format!("mock_doc_{i}"), Box::new(mock_td));
}
map
}
let framework = Framework::new("any_dir", String::from("dummy"),
&gather_mock_documents);
Framework::new
是这样的:
pub fn new(document_root_path: &str, index_name: String,
gather_closure: &dyn Fn(WalkDir, &Weak<Framework>) ->
HashMap<String, Box<dyn TextDocument>>) -> Rc<Self> {
let walker = WalkDir::new(document_root_path);
let hf = Rc::new_cyclic(|this: &std::rc::Weak<Framework>|
Framework{
index_name,
root_documents_path_str: String::from(document_root_path),
text_doc_map: gather_closure(walker, this),
}
);
hf
}
明白了...感谢 Chayim Friedman 的建议。
struct MockTextDocument {
pub framework: Weak<HandlingFramework>,
parse_count: Rc<RefCell<i32>>,
}
impl TextDocument for MockTextDocument {
fn get_framework(&self) -> &Weak<HandlingFramework>{
&self.framework
}
fn parse(&self) -> Result<()> {
*self.parse_count.borrow_mut() += 1;
Ok(())
}
}
#[test]
fn each_text_document_is_parsed_in_framework_create_index() -> Result<()>{
let parse_count = Rc::new(RefCell::new(0));
let gather_mock_documents = |_: WalkDir, this: &Weak<HandlingFramework>| -> HashMap<String, Box<dyn TextDocument>> {
let mut map: HashMap<String, Box<dyn TextDocument>> = HashMap::new();
for i in 0..3 {
let mock_td = MockTextDocument {
framework: this.clone(),
parse_count: parse_count.clone(),
};
map.insert(format!("mock_doc_{i}"), Box::new(mock_td));
}
map
};
let framework = HandlingFramework::new("any_dir", String::from("dummy"),
&DummyConfiguror, &gather_mock_documents);
println!("framework type {}", type_name_of_val(&framework));
assert_eq!(framework.text_doc_map.len(), 3, "len was {}", framework.text_doc_map.len());
let _ = framework.create_index();
assert_eq!(*parse_count.borrow(), 3);
Ok(())
}