如何在QuickCheck测试中默默捕捉恐慌? [英] How can I silently catch panics in QuickCheck tests?
问题描述
在我的 overflower_support 板条箱的测试中,我发现有很多关于已使用std::panic::catch_unwind(_)
处理的紧急情况.这有点不幸,因为它掩盖了可能发生的实际错误.消息如下:
In the tests of my overflower_support crate, I have found that I get a lot of spurious reports of panics which are already handled using std::panic::catch_unwind(_)
. This is a bit unfortunate, as it obscures the real errors that may happen. The messages look like:
thread 'safe' panicked at 'arithmetic overflow', src/lib.rs:56
为平息那些分散注意力的消息,我引入了dont_panic(..)
函数,该函数劫持了应急处理程序,调用了一个闭包,并在完成后重置了应急处理程序,返回了闭包结果.看起来像这样:
To quell those distracting messages, I introduced the dont_panic(..)
function, which hijacks the panic handler, calls a closure and resets the panic handler when done, returning the closures result. It looks like this:
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
}
但是,在函数中使用此函数进行一些令人惊讶的检查不仅可以平息所需的消息,还可以平息quickcheck的错误输出,这对我来说显然很有价值.即使将测试限制在一个线程中,也会发生这种情况.
However, using this function within the function to check somewhat surprisingly not only quells the desired messages, but also quickcheck's error output, which is obviously valuable to me. This occurs even when limiting tests to one thread.
#[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的恐慌可见的同时,从代码中隐藏捕获的恐慌?
How can I hide the caught panics from my code while keeping QuickCheck's panics visible?
推荐答案
我的方法存在两个问题:
There were two problems with my approach:
- 测试是并行运行的(而quickcheck似乎增加了
本身,因为
-j 1
似乎无法平息恐慌消息.) - 消息被写入(或被
set_hook(_)
禁止显示)否 是否有catch_unwind(_)
无关紧要.
- The tests run in parallel (and quickcheck appears to add some parallelism of
its own, as
-j 1
appears ineffective to quell the panic messages). - The message gets written (or otherwise suppressed by
set_hook(_)
) no matter if there's acatch_unwind(_)
or not.
但是,dpc.pw区分恐慌处理程序中文件的想法是
发现.我更改了方法,以在调用install_handler()
函数之前
调用quickcheck(_)
,我将在此处完整复制:
However, dpc.pw's idea to distinguish based on files in the panic handler was
spot-on. I changed my approach to call an install_handler()
function before
calling quickcheck(_)
, which I reproduce here in full:
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
代码也可能会崩溃).
This will quell the panic messages if the panic came from src/lib.rs
(which
is my overflower_support
code) or somewhere from /num/mod.rs
(because the
Rust libcore
code may panic, too).
请注意,您可以省略Once
,但这会为处理程序添加多个
并增加堆栈跟踪的大小,同时加剧
测试性能.
Note that you could omit the Once
, but this would add the handler multiple
times and increase the size of stack traces considerably while exacerbating
test performance.
这篇关于如何在QuickCheck测试中默默捕捉恐慌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!