請考慮以下功能:
pub fn shiny_function(&mut self, cb: Arc<Mutex<dyn FnMut(usize) Send>>) {
// Do stuff here...
}
現在,問題是,我如何撰寫一個單元測驗來檢查回呼(閉包)引數是否等于某個值?
顯而易見的解決方案如下所示:
#[test]
fn progress_cb() {
let cut = ... // cut stands for Class Under Test
cut.shiny_function(Arc::new(Mutex::new(move |percent| {
// Assert here maybe? I don't know.
})));
cut.shiny_function();
// Or maybe assert it somehow here? I don't know.
}
但問題是測驗甚至在回呼被呼叫之前就完成了。我如何告訴測驗工具等到回呼被呼叫?
uj5u.com熱心網友回復:
您可以使用標準庫中提供的常規并發結構來解決此問題。在這個例子中,我使用了一個屏障來確保在測驗函式退出之前到達閉包的末尾。我創建值為 2 的屏障,因為在兩個執行緒上釋放屏障之前必須呼叫兩次等待。shiny_function多次呼叫時可能不希望出現這種行為,因此您還可以替換另一個僅在單個位置阻塞的并發結構。
use std::sync::{Arc, Barrier};
#[test]
fn progress_cb() {
let cut = ... // cut stands for Class Under Test
// Create a barrier for this thread and clone it to move into the closure
let barrier = Arc::new(Barrier::new(2));
let barrier_clone = barrier.clone();
cut.shiny_function(Arc::new(Mutex::new(move |percent| {
// Perform tests
assert_eq!(percent, foo);
// Once we finish we can trigger the barrier so the outer thread can continue
barrier_clone.wait();
})));
// Don't exit the function until the barrier has been resolved in the callback
barrier.wait();
}
編輯:shiny_function如果由于每次呼叫的閉包阻塞并在單個測驗函式中阻止以后的呼叫,障礙開始成為問題,您可以使用這里的結構。
use std::sync::{Arc, Mutex, Condvar};
pub struct SingleBlockingBarrier {
target: u32,
counter: Mutex<u32>,
lock: Condvar,
}
impl SingleBlockingBarrier {
pub fn new(target: u32) -> Arc<Self> {
Arc::new(SingleBlockingBarrier {
target,
counter: Mutex::new(0),
lock: Condvar::new(),
})
}
pub fn signal(&self) {
let mut guard = self.counter.lock().unwrap();
*guard = 1;
if *guard >= self.target {
self.lock.notify_all();
}
}
// Block until signal has been called the target number of times
pub fn block_until_finished(&self) {
let mut guard = self.counter.lock().unwrap();
loop {
if *guard >= self.target {
return;
}
guard = self.lock.wait(guard).unwrap();
}
}
}
#[test]
fn progress_cb() {
let cut = ... // cut stands for Class Under Test
// Create a barrier for this thread and clone it to move into the closure
let barrier = SingleBlockingBarrier::new(10);
for _ in 0..10 {
let barrier_clone = barrier.clone();
cut.shiny_function(Arc::new(Mutex::new(move |percent| {
// Perform tests
assert_eq!(percent, foo);
// Notify barrier that a worker has finished without blocking
barrier_clone.signal();
})));
}
// Block until all non-blocking barriers have been reached
barrier.block_until_finished();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/410565.html
標籤:
下一篇:如何測驗內部功能
