我在src
目录中有一个包含生产代码的箱子,在tests
目录中有一个集成测试。生产代码使用log
宏。
我想在运行集成测试时初始化一个全局记录器(例如env_logger::init().unwrap();
)有几个测试并且没有定义测试顺序,所以我不知道我应该在哪个测试中放置initialize命令。
有什么方法可以做得很好吗?也许通过覆盖测试main
功能?
现在没有好办法做这种内置的东西。
您可以编写一个宏,在每次测试之前插入某种初始化调用,但这样就足够了。
你可以使用这样的东西:
use std::sync::{Once, ONCE_INIT};
static INIT: Once = ONCE_INIT;
/// Setup function that is only run once, even if called multiple times.
fn setup() {
INIT.call_once(|| {
env_logger::init().unwrap();
});
}
然后在每次测试开始时简单地调用setup()
。
最初基于this blogpost。
现在,您可以在每个测试的顶部重新初始化记录器并忽略错误。这不是一个漂亮的解决方案,但它的工作原理非常安全。
let _ = env_logger::init();
// your test code...
我已经观察到cargo test
按字母顺序运行测试,因此我设计了一个非常脏的黑客来初始化记录器。
aaa_testing
的模块,它位于箱子的根部。#[test]
fn initialize_logger() {
env_logger::init();
}
是的我确实创建了一个始终通过的测试,但是如果你想测试初始化记录器,你可以做一个assert!(env_logger::try_init().is_ok());
Shepmaster指出,cargo test
异步运行测试,可能使前几个测试的记录不可靠。为了防止这种情况,可以在同一个线程中运行测试。 (这会导致性能问题,因此如果您需要多个线程来测试项目,则不应使用此答案。)
如果要控制同时运行的测试用例的数量,请将
--test-threads
选项传递给测试二进制文件:cargo test -- --test-threads=1
latest documentation has a recommendation:
#[cfg(test)]
mod tests {
fn init() {
let _ = env_logger::builder().is_test(true).try_init();
}
#[test]
fn it_works() {
info!("This record will be captured by `cargo test`");
assert_eq!(2, 1 + 1);
}
}