我如何在 QuickCheck 测试中悄悄捕捉恐慌?
How can I silently catch panics in QuickCheck tests?
在我的 overflower_support 箱子的测试中,我发现我收到了很多虚假的恐慌报告,这些报告已经使用 std::panic::catch_unwind(_)
处理了。这有点不幸,因为它掩盖了可能发生的真正错误。消息如下所示:
thread 'safe' panicked at 'arithmetic overflow', src/lib.rs:56
为了平息那些分散注意力的消息,我引入了 dont_panic(..)
函数,它劫持了恐慌处理程序,调用闭包并在完成时重置恐慌处理程序,返回闭包结果。它看起来像这样:
fn dont_panic<F, A, R>(args: A, f: F) -> R
where F: Fn(A) -> R
{
let p = panic::take_hook();
panic::set_hook(Box::new(|_| ()));
let result = f(args);
panic::set_hook(p);
result
}
然而,在函数中使用这个函数来检查有点令人惊讶,不仅可以平息所需的消息,而且还可以快速检查错误输出,这对我来说显然很有价值。即使将测试限制为一个线程也会发生这种情况。
#[test]
fn test_some_panic() {
fn check(x: usize) -> bool {
let expected = if x < 256 { Some(x) } else { None };
let actual = dont_panic(|| panic::catch_unwind(|| { assert!(x < 256); x }).ok());
expected == actual
}
quickcheck(check as fn(usize) -> bool);
}
如何在保持 QuickCheck 的恐慌可见的同时从我的代码中隐藏捕获的恐慌?
默认的恐慌处理程序正在 stderr 上无条件地打印恐慌信息。
我的方法有两个问题:
- 并行测试 运行(而且 quickcheck 似乎增加了一些并行性
它自己的,因为
-j 1
似乎无法平息恐慌消息)。
- 消息已写入(或被
set_hook(_)
抑制)否
不管有没有catch_unwind(_)
。
然而,dpc.pw在恐慌处理程序中根据文件进行区分的想法是
发现。我之前改变了调用 install_handler()
函数的方法
调用 quickcheck(_)
,我在此处完整复制:
use std::panic;
use std::sync::{Once, ONCE_INIT};
static HANDLER : Once = ONCE_INIT;
fn install_handler() {
HANDLER.call_once(|| {
let p = panic::take_hook();
panic::set_hook(Box::new(move|info| {
if info.location().map_or(false, |l| l.file() != "src/lib.rs" &&
!l.file().ends_with("/num/mod.rs")) {
p(info);
}
}));
})
}
如果恐慌来自 src/lib.rs
(这
是我的 overflower_support
代码)或来自 /num/mod.rs
的某处(因为
Rust libcore
代码也可能会崩溃。
请注意,您可以省略 Once
,但这会增加多个处理程序
时间并显着增加堆栈跟踪的大小,同时加剧
测试性能。
我遇到了同样的问题和其他一些问题,最后我写了一个 crate 来解决它们:
有了它,您的示例可能会在 "quiet" 线程中由 运行 解决(假设您对具体使用 catch_unwind
不感兴趣):
use panic_control::spawn_quiet;
#[test]
fn test_some_panic() {
fn check(x: usize) -> bool {
let expected = if x < 256 { Some(x) } else { None };
let h = spawn_quiet(|| { assert!(x < 256); x });
let actual = h.join().ok();
expected == actual
}
quickcheck(check as fn(usize) -> bool);
}
在我的 overflower_support 箱子的测试中,我发现我收到了很多虚假的恐慌报告,这些报告已经使用 std::panic::catch_unwind(_)
处理了。这有点不幸,因为它掩盖了可能发生的真正错误。消息如下所示:
thread 'safe' panicked at 'arithmetic overflow', src/lib.rs:56
为了平息那些分散注意力的消息,我引入了 dont_panic(..)
函数,它劫持了恐慌处理程序,调用闭包并在完成时重置恐慌处理程序,返回闭包结果。它看起来像这样:
fn dont_panic<F, A, R>(args: A, f: F) -> R
where F: Fn(A) -> R
{
let p = panic::take_hook();
panic::set_hook(Box::new(|_| ()));
let result = f(args);
panic::set_hook(p);
result
}
然而,在函数中使用这个函数来检查有点令人惊讶,不仅可以平息所需的消息,而且还可以快速检查错误输出,这对我来说显然很有价值。即使将测试限制为一个线程也会发生这种情况。
#[test]
fn test_some_panic() {
fn check(x: usize) -> bool {
let expected = if x < 256 { Some(x) } else { None };
let actual = dont_panic(|| panic::catch_unwind(|| { assert!(x < 256); x }).ok());
expected == actual
}
quickcheck(check as fn(usize) -> bool);
}
如何在保持 QuickCheck 的恐慌可见的同时从我的代码中隐藏捕获的恐慌?
默认的恐慌处理程序正在 stderr 上无条件地打印恐慌信息。
我的方法有两个问题:
- 并行测试 运行(而且 quickcheck 似乎增加了一些并行性
它自己的,因为
-j 1
似乎无法平息恐慌消息)。 - 消息已写入(或被
set_hook(_)
抑制)否 不管有没有catch_unwind(_)
。
然而,dpc.pw在恐慌处理程序中根据文件进行区分的想法是
发现。我之前改变了调用 install_handler()
函数的方法
调用 quickcheck(_)
,我在此处完整复制:
use std::panic;
use std::sync::{Once, ONCE_INIT};
static HANDLER : Once = ONCE_INIT;
fn install_handler() {
HANDLER.call_once(|| {
let p = panic::take_hook();
panic::set_hook(Box::new(move|info| {
if info.location().map_or(false, |l| l.file() != "src/lib.rs" &&
!l.file().ends_with("/num/mod.rs")) {
p(info);
}
}));
})
}
如果恐慌来自 src/lib.rs
(这
是我的 overflower_support
代码)或来自 /num/mod.rs
的某处(因为
Rust libcore
代码也可能会崩溃。
请注意,您可以省略 Once
,但这会增加多个处理程序
时间并显着增加堆栈跟踪的大小,同时加剧
测试性能。
我遇到了同样的问题和其他一些问题,最后我写了一个 crate 来解决它们:
有了它,您的示例可能会在 "quiet" 线程中由 运行 解决(假设您对具体使用 catch_unwind
不感兴趣):
use panic_control::spawn_quiet;
#[test]
fn test_some_panic() {
fn check(x: usize) -> bool {
let expected = if x < 256 { Some(x) } else { None };
let h = spawn_quiet(|| { assert!(x < 256); x });
let actual = h.join().ok();
expected == actual
}
quickcheck(check as fn(usize) -> bool);
}