Rust目录测试工具库dir-test的使用,提供高效文件系统目录操作与测试功能
Rust目录测试工具库dir-test的使用,提供高效文件系统目录操作与测试功能
dir-test
提供了一个宏,可以从目录中的文件生成单个测试用例。
使用
在您的 Cargo.toml
中添加以下依赖:
[dev-dependencies]
dir-test = "0.4"
基本用法
use dir_test::{dir_test, Fixture};
#[dir_test(
dir: "$CARGO_MANIFEST_DIR/fixtures",
glob: "**/*.txt",
)]
fn mytest(fixture: Fixture<&str>) {
// 文件内容和文件的绝对路径如下获取
let content = fixture.content();
let path = fixture.path();
// 在此处编写测试代码
// ...
}
假设您的项目结构如下,则上述代码会生成两个测试用例 mytest__foo()
和 mytest__fixtures_a_bar()
。
my-crate/
├─ fixtures/
│ ├─ foo.txt
│ ├─ fixtures_a/
│ │ ├─ bar.txt
├─ src/
│ ├─ ...
│ ├─ lib.rs
├─ Cargo.toml
├─ README.md
🔽
#[test]
fn mytest__foo() {
mytest(fixture);
}
#[test]
fn mytest__fixtures_a_bar() {
mytest(fixture);
}
注意: dir
参数必须指定为绝对路径,因为当前过程宏系统的限制。可以考虑使用环境变量,dir-test
库会在内部解析环境变量。
自定义加载器
您可以指定一个自定义加载器函数来从文件路径加载文件内容。加载器将传递 &'static str
文件路径,并可以返回任意类型。
use dir_test::{dir_test, Fixture};
#[dir_test(
dir: "$CARGO_MANIFEST_DIR/fixtures",
glob: "**/*.txt",
loader: std::fs::read_to_string,
)]
fn test(fixture: Fixture<std::io::Result<String>>) {
let content = fixture.content().unwrap();
// ...
}
如果未指定加载器函数,则默认内容类型为 &'static str
。
自定义测试名称
可以通过指定 postfix
参数来自定义测试名称。postfix
会附加到测试名称后面。
use dir_test::{dir_test, Fixture};
#[dir_test(
dir: "$CARGO_MANIFEST_DIR/fixtures",
glob: "**/*.txt",
postfix: "custom", // `_custom` 会附加到测试名称
)]
fn test(fixture: Fixture<std::io::Result<String>>) {
// ...
}
测试属性
测试属性可以通过 dir_test_attr
属性指定。dir_test_attr
中的属性将应用于所有生成的测试。
use dir_test::{dir_test, Fixture};
#[dir_test(
dir: "$CARGO_MANIFEST_DIR/fixtures",
glob: "**/*.txt",
)]
#[dir_test_attr(
#[wasm_bindgen_test]
#[cfg(target_family = "wasm")]
)]
fn wasm_test(fixture: Fixture<std::io::Result/String>>) {
// ...
}
注意: dir_test_attr
属性必须在 dir_test
之后指定。
返回值类型
测试可以有返回值类型,允许在测试中使用 Result<T, E>
类型。
use dir_test::{dir_test, Fixture};
#[dir_test(
dir: "$CARGO_MANIFEST_DIR/fixtures",
glob: "**/*.txt",
)]
fn test(fixture: Fixture<&str>) -> std::io::Result<()> {
// ...
}
完整示例
下面是一个完整的示例,展示如何使用 dir-test
进行目录测试:
- 首先在项目中创建测试目录和文件:
my_project/
├─ tests/
│ ├─ fixtures/
│ │ ├─ test1.txt
│ │ ├─ subdir/
│ │ │ ├─ test2.txt
├─ Cargo.toml
- 在
Cargo.toml
中添加依赖:
[dev-dependencies]
dir-test = "0.4"
- 创建测试文件
tests/directory_tests.rs
:
use dir_test::{dir_test, Fixture};
#[dir_test(
dir: "$CARGO_MANIFEST_DIR/tests/fixtures",
glob: "**/*.txt",
loader: std::fs::read_to_string,
)]
fn test_file_content(fixture: Fixture<std::io::Result<String>>) -> std::io::Result<()> {
let content = fixture.content()?;
let path = fixture.path();
println!("Testing file: {}", path.display());
println!("Content length: {}", content.len());
// 这里可以添加具体的测试逻辑
assert!(!content.is_empty());
Ok(())
}
#[dir_test(
dir: "$CARGO_MANIFEST_DIR/tests/fixtures",
glob: "**/*.txt",
postfix: "check_extension",
)]
fn test_file_extension(fixture: Fixture<&str>) {
let path = fixture.path();
assert_eq!(path.extension().unwrap(), "txt");
}
- 运行测试:
cargo test
这个示例会:
- 从
tests/fixtures
目录及其子目录中查找所有.txt
文件 - 生成两个测试集:
test_file_content
测试每个文件的内容不为空test_file_extension_check_extension
测试每个文件的扩展名是.txt
每个找到的 .txt
文件都会生成对应的测试用例,测试名称会自动包含文件路径信息。
Rust目录测试工具库dir-test的使用指南
dir-test
是一个专门用于文件系统目录操作与测试的Rust库,它提供了高效、便捷的方式来创建、管理和验证目录结构,特别适合在单元测试和集成测试场景中使用。
主要功能
- 临时目录的创建与自动清理
- 目录结构的快速搭建
- 文件内容的生成与验证
- 目录比较与断言
安装方法
在Cargo.toml
中添加依赖:
[dependencies]
dir-test = "0.3"
基本使用方法
1. 创建临时目录
use dir_test::{dir_test, Fixture};
#[dir_test]
fn test_example() {
// 在当前测试函数中创建一个临时目录
let fixture = Fixture::blank();
// 获取临时目录路径
let temp_dir = fixture.path();
println!("临时目录: {:?}", temp_dir);
// 测试结束后自动删除临时目录
}
2. 使用预设目录结构
use dir_test::{dir_test, Fixture};
#[dir_test(
dir = "fixtures/my_test_case", // 指定预设目录
)]
fn test_with_fixture() {
let fixture = Fixture::current();
// 读取预设目录中的文件
let content = std::fs::read_to_string(fixture.path().join("example.txt")).unwrap();
assert_eq!(content, "Hello, dir-test!");
}
3. 动态创建目录结构
use dir_test::{dir_test, Fixture};
#[dir_test]
fn test_dynamic_creation() {
let fixture = Fixture::blank();
// 创建子目录
fixture.create_dir("subdir");
// 创建文件并写入内容
fixture.create_file("subdir/file.txt", "Test content");
// 验证文件存在
assert!(fixture.path().join("subdir/file.txt").exists());
}
高级用法
1. 使用模板目录
use dir_test::{dir_test, Fixture};
#[dir_test(
fixture = "fixtures/template",
config = r#"
[files]
"config.toml" = { content = "port = 8080" }
"README.md" = { content = "# Project\n\nTest project" }
"#
)]
fn test_with_template() {
let fixture = Fixture::current();
// 模板文件和动态生成的文件都可用
assert!(fixture.path().join("existing_file.txt").exists());
assert!(fixture.path().join("config.toml").exists());
}
2. 目录比较测试
use dir_test::{dir_test, Fixture, assert_dir_eq};
use std::path::Path;
#[dir_test]
fn test_directory_comparison() {
let fixture = Fixture::blank();
// 创建预期目录结构
fixture.create_dir("expected");
fixture.create_file("expected/file1.txt", "content1");
fixture.create_file("expected/file2.txt", "content2");
// 创建实际目录结构
fixture.create_dir("actual");
fixture.create_file("actual/file1.txt", "content1");
fixture.create_file("actual/file2.txt", "content2");
// 比较两个目录
assert_dir_eq!(
fixture.path().join("expected"),
fixture.path().join("actual")
);
}
配置选项
dir-test
支持通过属性宏配置测试环境:
#[dir_test(
dir = "fixtures/base", // 基础目录
fixture = "fixtures/template", // 模板目录
config = r#"
[files]
"dynamic.txt" = { content = "Generated content" }
"#,
clean = false // 测试结束后不自动清理
)]
fn test_with_config() {
// 测试代码
}
实际应用示例
测试文件处理函数
use dir_test::{dir_test, Fixture};
fn process_directory(dir: &std::path::Path) -> usize {
// 假设这是一个处理目录的函数,返回处理的文件数
std::fs::read_dir(dir).unwrap().count()
}
#[dir_test(
fixture = "fixtures/sample_data",
config = r#"
[files]
"new_file.txt" = { content = "additional file" }
"#
)]
fn test_process_directory() {
let fixture = Fixture::current();
let file_count = process_directory(fixture.path());
// 验证处理了正确数量的文件
assert_eq(file_count, 3); // 假设fixture/sample_data有2个文件,加上动态创建的1个
}
完整示例代码
下面是一个结合了多种功能的完整示例:
use dir_test::{dir_test, Fixture, assert_dir_eq};
use std::fs;
// 测试文件处理函数 - 统计目录中特定扩展名的文件数量
fn count_files_by_extension(dir: &std::path::Path, ext: &str) -> usize {
dir.read_dir()
.unwrap()
.filter_map(|entry| {
let entry = entry.unwrap();
if entry.path().extension().map(|e| e == ext).unwrap_or(false) {
Some(entry.path())
} else {
None
}
})
.count()
}
#[dir_test(
fixture = "fixtures/template", // 使用模板目录
config = r#"
[files]
"config.toml" = { content = "port = 8080" }
"data.json" = { content = "{}" }
"log.txt" = { content = "some logs" }
"#,
clean = true // 测试结束后自动清理
)]
fn test_file_operations() {
let fixture = Fixture::current();
let temp_dir = fixture.path();
// 验证模板文件存在
assert!(temp_dir.join("existing_file.txt").exists());
// 验证动态创建的文件存在
assert!(temp_dir.join("config.toml").exists());
assert!(temp_dir.join("data.json").exists());
assert!(temp_dir.join("log.txt").exists());
// 测试文件处理函数
let json_count = count_files_by_extension(temp_dir, "json");
assert_eq!(json_count, 1);
let txt_count = count_files_by_extension(temp_dir, "txt");
assert_eq!(txt_count, 2); // existing_file.txt + log.txt
// 创建预期目录结构
let expected_dir = temp_dir.join("expected");
fs::create_dir(&expected_dir).unwrap();
fs::write(expected_dir.join("test1.txt"), "test").unwrap();
fs::write(expected_dir.join("test2.txt"), "test").unwrap();
// 创建实际目录结构
let actual_dir = temp_dir.join("actual");
fs::create_dir(&actual_dir).unwrap();
fs::write(actual_dir.join("test1.txt"), "test").unwrap();
fs::write(actual_dir.join("test2.txt"), "test").unwrap();
// 比较两个目录
assert_dir_eq!(expected_dir, actual_dir);
}
这个完整示例展示了:
- 使用模板目录和动态配置创建测试环境
- 测试自定义的文件处理函数
- 动态创建目录结构进行比较测试
- 自动清理测试环境
dir-test
库通过提供简洁的API和自动化的目录管理,大大简化了涉及文件系统操作的测试编写工作,是Rust生态中测试文件相关功能的理想选择。