如何在 Rust 测试中为所有测试函数创建具有作用域/生命周期的变量?

15

我有一个测试,在深入测试细节之前会初始化一个变量,我想做第二个测试时使用同一变量而不是复制初始化代码:

#[test]
fn test_one() {
    let root = Path::new("data/");
    // the rest of the test
}
#[test]
fn test_two() {
    let root = Path::new("data/");
    // the rest of the test
}

我认为 static 或者 const 不行,因为尺寸在前期不会被确定,但是 PathBuf.from(path) 可以解决这个问题,然而对于静态/常量变量,初始化表达式不能太复杂。

我看过 lazy_static,但是没有看到任何在测试中使用的例子。这是在看到编译器错误 "an extern crate loading macros must be at the crate root" 后得出的,网上搜索告诉我这是关于在 main() 之外的一些问题,但是测试函数没有 main 函数。

在 Java 中,我会定义变量然后在 setup() 方法中初始化,但是我在 Rust 中找不到这样的例子。


1
https://dev59.com/6F0a5IYBdhLWcg3wkpas#43093371 对我来说看起来不错(但我刚开始学Rust) - Günter Zöchbauer
1个回答

19

首先,请记住 Rust 测试是以 并行 方式运行的。这意味着任何共享的设置都需要是线程安全的。

并且不要复制初始化代码

你可以像避免复制 其他任何代码 一样来做:创建一个函数、创建一个类型、创建特性等等:

use std::path::PathBuf;

fn root() -> PathBuf {
    PathBuf::from("data/")
}

#[test]
fn test_one() {
    let root = root();
    // the rest of the test
}

#[test]
fn test_two() {
    let root = root();
    // the rest of the test
}

在Java中,我会先定义变量,然后在setup()方法中初始化它。

相反,可以创建一个名为Setup的结构体,其中包含所有这些变量,并将其构建为每个测试的第一件事:

use std::path::{Path, PathBuf};

struct Setup {
    root: PathBuf,
}

impl Setup {
    fn new() -> Self {
        Self {
            root: PathBuf::from("data/"),
        }
    }
}

#[test]
fn test_one() {
    let setup = Setup::new();
    let root: &Path = &setup.root;
    // the rest of the test
}

#[test]
fn test_two() {
    let setup = Setup::new();
    let root: &Path = &setup.root;
    // the rest of the test
}

但是在测试中我还没有看到过[lazy-static]的使用示例。

那是因为在测试中没有不同的使用方式,它只是代码:


但是我在测试中没有看到过 [lazy-static] 的使用示例,这是因为在测试中它的使用方式与普通代码并无区别:

use lazy_static::lazy_static; // 1.4.0
use std::path::Path;

lazy_static! {
    static ref ROOT: &'static Path = Path::new("data/");
}

#[test]
fn test_one() {
    let root = *ROOT;
    // the rest of the test
}

#[test]
fn test_two() {
    let root = *ROOT;
    // the rest of the test
}

另请参阅:


特别针对您的情况,通常情况下您不需要确切的Path,因为字符串切片实现了AsRef<Path>。换句话说,大多数接受Path的地方接受&str

static ROOT: &str = "data/";

#[test]
fn test_one() {
    let root = ROOT;
    // the rest of the test
}

#[test]
fn test_two() {
    let root = ROOT;
    // the rest of the test
}

如果setup函数执行一些繁重的初始化工作,例如进行第三方服务调用等,而您不希望为每个测试都重复执行该操作,您会怎么做? - Tamil Vendhan Kanagarasu
@TamilVendhanKanagarasu 这是答案中提到的lazy-static。另请参阅https://dev59.com/4V4c5IYBdhLWcg3wjq7R - Shepmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接