unit-testing - 在 Rust 的测试中创建、读取和删除文件时的奇怪行为

标签 unit-testing testing rust rust-cargo

我正在尝试为模块编写测试,模块本身并不重要。

测试部分看起来像这样。在这两个测试中,我试图做完全相同的事情:创建一个 JSON 文件,读取它并删除它(这些不是真正的测试,但这些操作需要从测试到测试重复)。

src/archive.rs

#[cfg(test)]
mod tests {
    use super::*;
    use std::{fs, path};
    use crate::tests;

    #[test]
    fn test_archive_tar_archive_test1() {
        tests::create_custom_settings(
            r#"{
                "tmp_path": "/tmp1",
                "archive_tmp_path": "/tmp1"
            }"#,
        );
        println!("reading {}", fs::read_to_string(tests::CUSTOM_SETTINGS_PATH).unwrap());
        tests::delete_custom_settings();
    }

    #[test]
    fn test_archive_tar_archive_test2() {
        tests::create_custom_settings(
            r#"{
                "tmp_path": "/tmp2",
                "archive_tmp_path": "/tmp2"
            }"#,
        );

        println!("reading {}", fs::read_to_string(tests::CUSTOM_SETTINGS_PATH).unwrap());
        tests::delete_custom_settings();
    }
}

第二个文件和第一个一样基本,这些是多个模块中使用的通用部分:

src/tests.rs

use std::fs;

pub const CUSTOM_SETTINGS_PATH: &str = "/tmp/hvtools_custom_settings.json";

pub fn create_custom_settings(file_data: &str) {
    println!("writing {}", file_data);
    match fs::write(CUSTOM_SETTINGS_PATH, file_data) {
        Ok(_) => {},
        Err(e) => panic!(
            "Could not create custom settings file under '{}': {}",
            CUSTOM_SETTINGS_PATH, e
        ),
    };
}

pub fn delete_custom_settings() {
    match fs::remove_file(CUSTOM_SETTINGS_PATH) {
        Ok(_) => {},
        Err(e) => panic!(
            "Could not delete custom settings file under '{}': {}",
            CUSTOM_SETTINGS_PATH, e
        ),
    };
}

运行这些测试时,我每次都差不多,但略有不同:

running 2 tests
writing {
                "tmp_path": "/tmp1",
                "archive_tmp_path": "/tmp1"
            }
writing {
                "tmp_path": "/tmp2",
                "archive_tmp_path": "/tmp2"
            }
reading {
                "tmp_path": "/tmp2",
                "archive_tmp_path": "/tmp2"
            }
reading {
                "tmp_path": "/tmp2",
                "archive_tmp_path": "/tmp2"
            }
thread 'archive::tests::test_archive_tar_archive_test2' panicked at 'Could not delete custom settings file under '/tmp/hvtools_custom_settings.json': No such file or directory (os error 2)', src/tests.rs:19:19

正如我们所见:
  • 在第一个测试中读取文件返回在第二个测试中写入的值
  • 尝试在第二个测试中删除 JSON 文件失败(读取工作时)

  • 有时两个测试都会读取第一次测试中写入的内容,有时第一次读取尝试会返回一个空字符串(结果会随着代码的变化而变化):

    running 2 tests
    writing {
                    "tmp_path": "/tmp1",
                    "archive_tmp_path": "/tmp1"
                }
    writing {
                    "tmp_path": "/tmp2",
                    "archive_tmp_path": "/tmp2"
                }
    reading 
    reading {
                    "tmp_path": "/tmp2",
                    "archive_tmp_path": "/tmp2"
                }
    

    它是一个物理文件系统(没有 NFS 共享或其他东西)。另外,作为旁注,如果我像这样将第二个测试的内容移动到第一个测试:

    fn test_archive_tar_archive_test1() {
        tests::create_custom_settings(
            r#"{
                    "tmp_path": "/tmp1",
                    "archive_tmp_path": "/tmp1"
                }"#,
        );
        println!(
            "reading {}",
            fs::read_to_string(tests::CUSTOM_SETTINGS_PATH).unwrap()
        );
        tests::delete_custom_settings();
    
        tests::create_custom_settings(
            r#"{
                    "tmp_path": "/tmp2",
                    "archive_tmp_path": "/tmp2"
                }"#,
        );
    
        println!(
            "reading {}",
            fs::read_to_string(tests::CUSTOM_SETTINGS_PATH).unwrap()
        );
        tests::delete_custom_settings();
    }
    

    一切都按预期工作。尝试添加 thread::sleep ,似乎并没有改变结果。

    我究竟做错了什么?

    最佳答案

    测试并行运行,因此访问相同路径的两个测试很可能会相互干扰。在每个测试中使用不同的路径来防止这种情况。

    或者,您可以强制测试在单个线程中按顺序运行:

    cargo test -- --test-threads=1
    

    关于unit-testing - 在 Rust 的测试中创建、读取和删除文件时的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61661001/

    相关文章:

    rust - 火箭内的 Handlebars helper

    rust - 如何在 MPSC 接收器中使用 Hyper 客户端?

    c# - Assert.Fail 不会使测试失败?

    c# - 使用 Moq 针对异步方法设置 C# 测试

    testing - OCaml - 测试签名中未包含的函数

    java - 如何在 Maven 中清理测试源?

    c# - 是否可以在 SonarQube 中导入 OpenCover/result?

    unit-testing - 对 Java 方法进行单元测试

    安卓单元测试 : clearing prefs before testing activity

    listview - 虚拟 ListView 不显示任何文本