如何在 Rust 中运行任何测试之前运行设置代码?
Posted
技术标签:
【中文标题】如何在 Rust 中运行任何测试之前运行设置代码?【英文标题】:How to run setup code before any tests run in Rust? 【发布时间】:2019-09-19 07:39:04 【问题描述】:我有一个 Rust 应用程序(一个简单的解释器),需要在环境可用之前进行一些设置(初始化一个 repo)。
我了解 Rust 以多线程方式运行其测试(通过 cargo test),因此我需要在任何测试运行之前初始化 repo。我还需要每次运行只执行一次,而不是在每次测试之前。
在 Java 的 JUnit 中,这将通过 @BeforeClass(或 JUnit 5 中的 @BeforeAll)方法来完成。我怎样才能在 Rust 中实现同样的目标?
【问题讨论】:
【参考方案1】:没有任何内置功能可以做到这一点,但这应该会有所帮助(您需要在每次测试开始时调用initialize()
):
use std::sync::Once;
static INIT: Once = Once::new();
pub fn initialize()
INIT.call_once(||
// initialization code here
);
【讨论】:
【参考方案2】:如果您使用ctor crate,您可以利用在运行任何测试之前运行的全局构造函数。
这是一个初始化流行的env_logger crate 的示例(假设您已将ctor
添加到Cargo.toml
文件中的[dev-dependencies]
部分):
#[cfg(test)]
#[ctor::ctor]
fn init()
env_logger::init();
函数名不重要,你可以随便命名。
【讨论】:
我应该把这个放到每个.rs
文件中吗?【参考方案3】:
为了给人们更多的想法(例如,如何不在每次测试中调用setup
),您可以做的另一件事是编写这样的帮助程序:
fn run_test<T>(test: T) -> ()
where T: FnOnce() -> () + panic::UnwindSafe
setup();
let result = panic::catch_unwind(||
test()
);
teardown();
assert!(result.is_ok())
然后,在您自己的测试中,您可以这样使用它:
#[test]
fn test()
run_test(||
let ret_value = function_under_test();
assert!(ret_value);
)
您可以在此处阅读有关UnwindSafe
trait 和catch_unwind
的更多信息:https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
我在 Eric Opines 的 this medium article 中找到了这个测试助手的最初想法。
此外,rstest crate 具有 pytest-like 固定装置,您可以将其用作设置代码(与 Jussi Kukkonen's answer 结合使用:
use std::sync::Once;
use rstest::rstest;
static INIT: Once = Once::new();
pub fn setup() -> ()
INIT.call_once(||
// initialization code here
);
#[rstest]
fn should_success(setup: ())
// do your test
也许有一天 rstest 将获得范围支持,并且不再需要 Once
。
【讨论】:
以上是关于如何在 Rust 中运行任何测试之前运行设置代码?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Python 中的每个单元测试之前和之后运行特定代码
如何在测试失败后但在任何 @After 方法之前让 JUnit 4.8 运行代码?