我有下面的服务,它注册回调函数,以便在某个时期执行,由i64
标识。该服务具有回调向量(受Send + Fn() -> ()
traits约束)。每个回调可以执行多次(因此使用Fn
而不是FnOnce
或FnMut
)。需要Send
特征,因为回调将由其他线程注册,并且此服务将在后台运行。
目前为止一切顺利,但我想测试回调是否以应有的方式执行(即i64
历元在某个方向上滴答作响,这可能(也可能不会)导致回调被执行)。问题是我似乎想不出实现这一点的方法。我“我来自Golang,在Golang中注入一个模拟回调并Assert它是否被调用是非常容易的,因为编译器没有施加这样的限制,但是当我在Rust中使用相同的方法时,我最终得到了一个FnMut
,而不是Fn
。
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
struct Service<T: Send + Fn() -> ()> {
triggers: Arc<Mutex<HashMap<i64, Vec<Box<T>>>>>,
}
impl<T: Send + Fn() -> ()> Service<T> {
pub fn build() -> Self {
Service {
triggers: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn poll(&'static self) {
let hs = Arc::clone(&self.triggers);
tokio::spawn(async move {
loop {
// do some stuff and get `val`
if let Some(v) = hs.lock().unwrap().get(&val) {
for cb in v.iter() {
cb();
}
}
}
});
()
}
pub fn register_callback(&self, val: i64, cb: Box<T>) -> () {
self.triggers
.lock()
.unwrap()
.entry(val)
.or_insert(Vec::new())
.push(cb);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_poll() {
let c = Service::build();
let mut called = false;
let cb = || called = true;
let h: i64 = 10;
c.register_callback(h, Box::new(cb));
assert_eq!(called, false);
}
}
关于如何在Rust中测试这种行为,有什么想法吗?我唯一能想到的可能是一些channel
,它将向测试传递一个本地值,并放弃对它的所有权?
1条答案
按热度按时间bvjveswy1#
最好的方法可能是使您的界面尽可能通用:
但是如果你不能泛化接口,你可以使用
AtomicBool
,如下所示: