gpt4 book ai didi

rust - rust 中的异步测试-如何从侧线程或由于 panic 而导致测试失败

转载 作者:行者123 更新时间:2023-12-03 11:47:31 24 4
gpt4 key购买 nike

我的库产生了一个侧线程,我正在尝试为其编写单元测试。
如果磁带库/模拟设备出现 panic ,我想通过测试。
我在用mockall mock
我的库代码是这样的:

    #[cfg_attr(test, automock)]
trait T1 { fn foo(&self, val: String) }
#[cfg_attr(test, automock)]
trait T2 { fn bar(&self, val: String) }
#[cfg_attr(test, automock)]
trait T3 { fn fa(&self, val: String) }

struct MyLib<A: T1 + Send + Sync, B:T2 + Send + Sync, C:T3 + Send + Sync> {f1: Arc<A>, f2: Arc<B>, f3: Arc<C>};

impl My_Lib {
fn do_something (&self) {
let f1 = Arc::clone(&self.f1);
let f2 = Arc::clone(&self.f2);
let f3 = Arc::clone(&self.f3);
thread::Builder::new().name("lib_thread".to_string()).spawn(move || {
// does something in an infinite loop with lots of logic and calls out to the traits which I am mocking in the tests
loop {
// some logic
// ....
f1.foo("something happened here which is interesting so check in test if it occured".to_string());
// more logic
// ...
f2.bar("more interesting things happened here".to_string());
// more logic
// ...
f3.fa("abc".to_string());
thread::sleep(interval)
}
});
}
}

#[test]
fn test_lib() {
let mut t1 = Mock_T1::new();
t1.expect_foo().return_const(()); // all sorts of mocks...
// all sorts of fancy logic

let mut c = Mock_T3::new();
c.expect_fa().withf(|x: String| {
// some complex assertion here which failed and it was called on "lib_thread"
// i.e.
assert!(x == "some interesting value which should be here!");
assert(false); // should make the test fail but instead get a panic on the thread
// thread 'lib_thread' panicked at 'MockT3::fa: No matching expectation found
// test is still running and never completes
}
//block the test from exiting until I want to finish
std::thread::park();
}
可重现的案例:
    fn should_fail() {
std::thread::spawn(|| {
loop {
assert!(false); // test should complete here
std::thread::sleep(Duration::from_secs(1));
}
});
}

#[test]
fn fail() {
should_fail();
std::thread::park();
}

最佳答案

测试工具仅检查它是否引发了 panic 的线程,您必须将自己线程内的 panic 传播到调用测试的线程。为此,您可以将JoinHandle返回到由thread::spawn创建的线程:

fn should_fail() -> std::thread::JoinHandle<()> {
std::thread::spawn(|| {
loop {
assert!(false);
std::thread::sleep(Duration::from_secs(1));
}
})
}
然后,您可以在句柄上调用 .join()JoinHandle::join()等待关联的线程完成。如果子线程出现紧急情况,则使用给 Err的参数返回 panic!。这样, panic 就会传播到主线程:
#[test]
fn test() {
let join_handle = should_fail();
// unwrap will panic if `should_fail` panics
join_handle.join().unwrap();
}
您可能不希望仅出于测试目的而返回 JoinHandle。但是 JoinHandle不仅如此。实际上, there was even discussion即将其标记为 #[must_use]!这是有关 Joining your threads的精彩文章。

还有其他几种方法可以等待线程完成而不会阻塞,例如使用 channel 或 here讨论的引用计数器。

关于rust - rust 中的异步测试-如何从侧线程或由于 panic 而导致测试失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64633517/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com