【问题标题】:How to move tests into a separate file for binaries in Rust's Cargo?如何将测试移动到 Rust Cargo 中二进制文件的单独文件中?
【发布时间】:2016-12-24 01:37:37
【问题描述】:

我使用 Cargo 创建了一个新的二进制文件:

cargo new my_binary --bin

my_binary/src/main.rs 中的函数可用于测试:

fn function_from_main() {
    println!("Test OK");
}

#[test]
fn my_test() {
    function_from_main();
}

cargo test -- --nocapture 按预期运行测试。

将此测试移至单独文件的最直接方法是什么(将function_from_main 保留在my_binary/src/main.rs 中)?

我尝试这样做,但不知道如何让 my_test 从单独的文件中调用 function_from_main

【问题讨论】:

    标签: testing rust rust-cargo


    【解决方案1】:

    Rust 编程语言a chapter dedicated to testing,您应该阅读它以获得基本理解。


    通常将单元测试(更允许访问代码内部的测试)放入每个特定文件的test 模块中:

    fn function_from_main() {
        println!("Test OK");
    }
    
    #[cfg(test)]
    mod test {
        use super::*;
        
        #[test]
        fn my_test() {
            function_from_main();
        }
    }
    

    模块可以移动到新文件中,尽管这对于单元测试模块来说并不常见:

    ma​​in.rs

    fn function_from_main() {
        println!("Test OK");
    }
    
    #[cfg(test)]
    mod test;
    

    test.rs

    use super::*;
    
    #[test]
    fn my_test() {
        function_from_main();
    }
    

    有关文件和模块如何相互映射的详细信息,请参阅Separating Modules into Different Files


    在单独文件中进行测试的更常见情况是集成测试。本书中的section devoted to tests outside of the crate 也涵盖了这些内容。这些类型的测试非常适合作为代码的使用者来执行代码。

    文档的该部分包括一个介绍性示例和描述性文本:

    我们在项目目录的顶层创建一个 tests 目录, src 旁边。 Cargo 知道在这个里面寻找集成测试文件 目录。然后,我们可以在此创建尽可能多的测试文件 目录,Cargo 会将每个文件单独编译 板条箱。

    让我们创建一个集成测试。仍然使用示例 11-12 中的代码 在 src/lib.rs 文件中,创建一个 tests 目录,创建一个新文件 命名为tests/integration_test.rs,输入示例11-13中的代码:

    文件名:tests/integration_test.rs

    use adder;
    
    #[test]
    fn it_adds_two() {
        assert_eq!(4, adder::add_two(2));
    }
    

    示例 11-13:adder crate 中函数的集成测试

    我们在代码顶部添加了use adder,我们不需要 单元测试。原因是测试目录中的每个测试都是 一个单独的板条箱,所以我们需要将我们的库带入每个测试 crate 的作用域。

    请注意,该函数被称为adder::add_two。有关 Rust 模块系统的更多详细信息,请参阅Packages, Crates, and Modules chapter

    由于这些测试会像用户一样运行您的 crate,如果您想测试一个二进制文件,您应该执行二进制文件。像assert_cmd 这样的板条箱可以帮助减轻这种测试的痛苦。

    在其他情况下,您应该将大型二进制文件分解为一个大型库和一个小型二进制文件。然后,您可以为库的公共 API 编写集成测试。

    另见:

    【讨论】:

    • 如何为executable(不是lib)编写集成测试(tests目录里面的测试)?然后extern crate <executable> 不起作用。
    • @Nawaz 如果您正在执行可执行文件的集成 测试,您可以像用户那样驱动它:通过类似std::process::Command 的方式运行构建的命令。否则你在谈论单元测试。
    • 使用带有集成测试的调试器通过生成单独的进程来测试 bin 是一种次优的开发人员体验。 :-(
    【解决方案2】:

    如果你有一个模块 foo.rs 并且想要将你的单元测试放在它旁边的一个名为 foo_test.rs 的文件中,你会发现这是Rust 并不总是会寻找子模块的地方。

    可以使用#[path]属性指定模块对应文件的位置:

    #[cfg(test)]
    #[path = "./foo_test.rs"]
    mod foo_test;
    

    这在博文Better location for unit tests in Rust中有解释。

    【讨论】:

    • 您为什么要不遗余力地将文件放在非惯用位置?将其放置为foo.rsfoo/tests.rs,就像所有其他模块一样。
    • 这里没有刺激,因为我不必处理您的代码!如果我遵循该语言的习语,而不是试图背负每种先前语言的所有包袱,我只会发现会变得更加顺畅。
    • 为什么需要#[path]?大多数人会使用mod foo_test,因为它看起来与lib.rs 中的相同,但他们得到的是file not found error。发生这种情况是因为当您使用 mod foo 时,foo.rs 中的所有代码现在都在模块 foo 的范围内 - 这会影响 mod 搜索的位置。所以在模块 foo 的范围内,@987654335 @ 查找 src/foo/mod_test.rssrc/foo/mod_test/mod.rs。头有点难缠。此外,在foo_test.rs 中,您可以编写use super::my_func 以访问foo.rsfoo 模块)的成员。
    • @Shepmaster 我认为这是一个非常酷的可能性,允许 ppl 将单元测试与其源分开,以防止污染源。实际上这是我阅读 rust 书后搜索的前几个问题,如果没有这种可能性,我可能会严重黑 rust,几乎不相信将单元测试和源代码混在一起是一种更易于维护的方式
    【解决方案3】:

    你是对的; function_from_mainmain.rs 之外无法访问。

    你需要创建一个src/lib.rs 并移动你想要测试的函数。然后您就可以在您的测试模块中使用extern crate my_binary;,并让您的函数出现在my_binary 命名空间下。

    【讨论】:

      【解决方案4】:

      为了修饰* @mmai 的回答:

      #[rustfmt::skip]
      #[cfg(test)]
      #[path = "./foo_test.rs"]
      mod foo_test;
      

      cargo fmt 似乎对新测试文件的路径不满意。如果有人有更好的解决方案,我会很高兴听到,因为我希望 cargo fmt 也能格式化我的测试文件!

      *抱歉:我将添加此作为对现有答案的评论,但我没有足够的声誉。

      【讨论】:

      【解决方案5】:

      我确实认为您应该遵循阅读 Rust 书籍测试章节的建议,但是,这仍然不能完全回答您的问题,如何分离测试和源文件

      假设您有一个lib.rs 源文件并想要一个test_lib.rs 文件。为此,您只需要:

      在你的lib.rs:

      mod test_lib;
      
      // rest of source
      

      然后在你的test_lib.rs:

      #[cfg(test)]
      use super::*;
      
      #[test]
      fn test1() {
          // test logic 
      }
      
      // more tests
      

      那么,你和cargo test 都应该高兴了。

      【讨论】:

        猜你喜欢
        • 2022-01-15
        • 1970-01-01
        • 2013-08-14
        • 2023-01-11
        • 1970-01-01
        • 2014-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多