我们可以在板条箱之间共享测试用途吗?

时间:2017-01-17 15:08:08

标签: unit-testing rust

我的crate-0有src/lib.rs,如下所示:

#[cfg(test)]
pub mod test_utils {
    pub struct OnlyInTests(pub usize);
    pub fn helper() -> usize { 999 }

    #[test]
    fn test_0() { let _ = OnlyInTests(helper()); }
}

我还有crate-1,我需要在crate-0中定义的测试框架:

extern crate crate_0;

#[cfg(test)]
pub mod test_utils {
    // This will error out - cannot find mod test_utils in crate_0
    use crate_0::test_utils::{OnlyInTests, helper()};

    #[test]
    fn test_1() { let _ = OnlyInTests(helper()); }
}

这里的代码很简单,可以复制粘贴,但实际上我有一些复杂的测试工具,我想在测试crate-1时使用它。

我无法将测试实用程序分离到不同的包中,因为我会得到循环依赖性错误:test_utils将取决于crate-0创建内容而crate-0将取决于{{1} } 用于检测)。我实际上也不想这样做,因为还有更多的板条箱,我想在依赖板条箱中使用它的测试工具。

1 个答案:

答案 0 :(得分:2)

两种解决方案有着截然不同的权衡:

实用程序的单独包装箱

将测试实用程序而不是测试放在新的包crate-0-testutils中。 让crate-0取决于crate-0-testutils; crate-0-testutils取决于crate-0; crate-1 dev-depend依赖crate-0-testutils并依赖于crate-0。

这不会创建循环依赖关系,因为dev依赖关系不会传播。由于dev依赖,你在crate-0中的测试仍然可以使用crate-0-testutils中的内容。

如果您创建的所有内容都具有此类实用程序,则最多可将您的lib crate数量增加一倍。

在所有包装箱中使用测试功能

Cargo.toml crate-0中创建一个不依赖于任何内容的功能:

[features]
testing = []

crate-1中的一个取决于上述内容:

testing = ["crate-0/testing"]

然后在未启用该功能时对每个包装箱进行第一次测试失败,以便更容易理解错误:

#[cfg(all(not(feature = "testing"),test))]
mod testusage {
    #[test]
    fn panic_without_testing_feature() {
        panic!("Please use the feature testing when running tests.\n\nUse: cargo test --features testing\n\n");
    }
}

仅在通过为其添加防护功能启用该功能时编译实用程序:

#[cfg(feature = "testing")]
fn testing_utility() {
}

这只会在每个包中添加一个功能,无论它依赖多少测试功能,但缺点是需要特殊的测试调用。

避免在任何crate wide依赖声明中添加此功能。将crate-0中的测试功能包含在crate-1的开发依赖项中,其中crate-1也与crate-0具有正常的依赖关系,从而导致货物构建crate-0即使在发布模式下,即使对于crate-1的构建目标也具有功能。