简体   繁体   English

在 Rust 单元测试工具中,如何等待回调被调用?

[英]In a Rust Unit Test harness, how do I wait for a callback to be called?

Please consider the following function:请考虑以下 function:

pub fn shiny_function(&mut self, cb: Arc<Mutex<dyn FnMut(usize) + Send>>) {
    // Do stuff here...
}

Now, the question is, how do I write a Unit Test that checks that the callback (closure) parameter is equal to some value?现在,问题是,我如何编写一个单元测试来检查回调(闭包)参数是否等于某个值?

The obvious solution looks something like this:显而易见的解决方案如下所示:

#[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.
}

But the thing is the test finishes before the callback is even called.但问题是测试甚至在回调被调用之前就完成了。 How can I tell the test harness to wait until the callback is called?我如何告诉测试工具等到回调被调用?

You can use the regular concurrency structs provided in the standard library to fix this issue.您可以使用标准库中提供的常规并发结构来解决此问题。 In this example, I use a barrier to ensure that the end of the closure is reached before the test function exits.在这个例子中,我使用了一个屏障来确保在测试 function 退出之前到达闭包的末端。 I create the barrier with a value of 2 since wait must be called twice before the barrier is released on both threads.我创建值为 2 的屏障,因为在两个线程上释放屏障之前必须调用两次等待。 This behavior might not be desirable when calling shiny_function multiple times so you could also substitute another concurrency structure that only blocks in a single location.当多次调用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();
}

Edit: Here is a struct you could use to if the barrier starts becoming an issue due to the closure blocking on every call and holding up later calls to shiny_function in a single test function.编辑:如果由于每次调用的闭包阻塞并在单个测试 function 中阻止以后对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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何测试在AngularJS单元测试中已调用此嵌套函数? - How do I test that this nested function was called in an AngularJS unit test? 创建测试工具(单元测试) - create test harness (unit test) 如何在JSON回调中执行猕猴桃单元测试? - How do I perform a kiwi unit test, inside a JSON callback? 如何编写验证子程序调用的单元测试? - How do I write a unit test that verifies a subroutine is called? 如何为这个在循环中调用的方法编写单元测试? - How do I write a unit test for this method that is called inside a loop? 如何编写确保发生恐慌的 Rust 单元测试? - How do I write a Rust unit test that ensures that a panic has occurred? 如何对从 ISR 调用的静态回调例程进行单元测试 - How to unit test static callback routine called from ISR 如何使用 Cypress 对在 React 组件上调用的回调函数进行单元测试 - How to unit test a callback function was called on a React component using Cypress 在Jasmine单元测试中,如何强制失败回调触发失败请求的结果? - In a Jasmine unit test, how do I force a failure callback to trigger that would result from a failed request? 带有Sinon的单元测试:如何测试回调内部的变量? - Unit Testing w/ Sinon: How do I test a variable inside of a Callback?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM