Rust资产测试工具库asset-test-utils的使用,高效管理测试资源与模拟资产环境
Rust资产测试工具库asset-test-utils的使用,高效管理测试资源与模拟资产环境
安装
在项目目录中运行以下Cargo命令:
cargo add asset-test-utils
或者在Cargo.toml中添加以下行:
asset-test-utils = "25.0.0"
基本使用示例
use asset_test_utils::{Asset, AssetRegistry, MockEnvironment};
// 创建模拟资产环境
let mut mock_env = MockEnvironment::new();
// 创建资产注册表
let mut registry = AssetRegistry::new();
// 注册测试资产
let asset1 = Asset::new("asset1", "path/to/asset1");
let asset2 = Asset::new("asset2", "path/to/asset2");
registry.register(asset1);
registry.register(asset2);
// 将注册表添加到模拟环境
mock_env.add_registry(registry);
// 在测试中使用模拟环境
let loaded_asset = mock_env.load_asset("asset1").unwrap();
assert_eq!(loaded_asset.id(), "asset1");
完整示例
use asset_test_utils::{Asset, AssetRegistry, MockEnvironment, AssetLoader};
use std::path::PathBuf;
#[test]
fn test_asset_loading() {
// 1. 设置模拟环境
let mut mock_env = MockEnvironment::new();
// 2. 创建测试资产
let assets = vec![
Asset::new("texture", "assets/textures/test.png"),
Asset::new("model", "assets/models/test.obj"),
Asset::new("shader", "assets/shaders/test.glsl"),
];
// 3. 创建并配置资产注册表
let mut registry = AssetRegistry::new();
for asset in assets {
registry.register(asset);
}
// 4. 将注册表添加到环境
mock_env.add_registry(registry);
// 5. 创建资产加载器
let loader = AssetLoader::new(mock_env);
// 6. 测试资产加载
let texture = loader.load("texture").unwrap();
assert_eq!(texture.path(), PathBuf::from("assets/textures/test.png"));
let model = loader.load("model").unwrap();
assert_eq!(model.path(), PathBuf::from("assets/models/test.obj"));
// 7. 测试不存在的资产
assert!(loader.load("non_existent").is_err());
}
高级功能
use asset_test_utils::{Asset, AssetRegistry, MockEnvironment, LoadBehavior, ErrorScenario};
#[test]
fn test_advanced_features() {
let mut env = MockEnvironment::new();
let mut registry = AssetRegistry::new();
// 配置资产加载行为
let mut asset = Asset::new("slow_asset", "path/to/slow");
asset.set_load_behavior(LoadBehavior::Delayed);
// 配置错误场景
let mut error_asset = Asset::new("error_asset", "path/to/error");
error_asset.set_error_scenario(ErrorScenario::LoadFailure);
registry.register(asset);
registry.register(error_asset);
env.add_registry(registry);
// 测试延迟加载
let loader = AssetLoader::new(env);
let slow = loader.load("slow_asset").unwrap();
assert!(!slow.is_loaded());
// 测试错误场景
assert!(loader.load("error_asset").is_err());
}
完整示例demo
下面是一个更完整的demo示例,展示了asset-test-utils在实际项目中的典型用法:
use asset_test_utils::{
Asset,
AssetRegistry,
MockEnvironment,
AssetLoader,
LoadBehavior,
ErrorScenario
};
use std::path::PathBuf;
// 自定义资产类型
#[derive(Debug)]
struct GameTexture {
id: String,
path: PathBuf,
width: u32,
height: u32
}
impl GameTexture {
fn new(id: &str, path: &str, width: u32, height: u32) -> Self {
Self {
id: id.to_string(),
path: PathBuf::from(path),
width,
height
}
}
}
#[test]
fn test_game_asset_system() {
// 1. 初始化模拟环境
let mut env = MockEnvironment::new();
// 2. 准备测试资产
let textures = vec![
("player", "assets/player.png", 64, 64),
("enemy", "assets/enemy.png", 32, 32),
("background", "assets/bg.png", 1024, 768)
];
// 3. 创建并配置资产注册表
let mut registry = AssetRegistry::new();
for (id, path, width, height) in textures {
// 创建自定义资产对象
let texture = GameTexture::new(id, path, width, height);
// 转换为通用Asset对象
let mut asset = Asset::new(id, path);
asset.set_custom_data(texture); // 存储自定义数据
// 设置不同的加载行为
match id {
"player" => asset.set_load_behavior(LoadBehavior::Immediate),
"enemy" => asset.set_load_behavior(LoadBehavior::Delayed),
"background" => {
asset.set_load_behavior(LoadBehavior::Immediate);
asset.set_error_scenario(ErrorScenario::LoadFailure);
},
_ => {}
}
registry.register(asset);
}
// 4. 将注册表添加到环境
env.add_registry(registry);
// 5. 测试不同场景
let loader = AssetLoader::new(env);
// 测试立即加载的资产
let player = loader.load("player").unwrap();
let player_data: &GameTexture = player.custom_data().unwrap();
assert_eq!(player_data.width, 64);
// 测试延迟加载的资产
let enemy = loader.load("enemy").unwrap();
assert!(!enemy.is_loaded());
// 测试配置了错误的资产
assert!(loader.load("background").is_err());
// 测试资产依赖
let mut dependency_asset = Asset::new("dependent", "path/to/dependent");
dependency_asset.add_dependency("player");
assert!(dependency_asset.dependencies().contains(&"player".to_string()));
}
这个demo展示了:
- 如何创建自定义资产类型
- 如何配置不同的加载行为
- 如何模拟错误场景
- 如何测试资产依赖关系
- 完整的工作流程演示
asset-test-utils可以有效简化资产相关代码的测试工作,特别是在游戏开发、图形应用等需要处理大量资源的场景中。
1 回复
Rust资产测试工具库asset-test-utils的使用指南
介绍
asset-test-utils
是一个专门为Rust测试设计的工具库,用于高效管理测试资源和模拟资产环境。它特别适合需要处理文件、数据库或其他外部资源的测试场景。
主要特性
- 自动化测试资源的创建和清理
- 模拟文件系统和资产环境
- 线程安全的测试资源管理
- 简化测试中的临时文件/目录处理
安装
在Cargo.toml中添加依赖:
[dev-dependencies]
asset-test-utils = "0.1" # 请使用最新版本号
完整示例代码
1. 临时目录完整示例
use asset_test_utils::TempDir;
use std::fs;
#[test]
fn test_file_operations() {
// 创建临时目录
let temp_dir = TempDir::new().expect("创建临时目录失败");
// 在临时目录中创建文件
let file_path = temp_dir.path().join("data.txt");
fs::write(&file_path, "测试数据").expect("写入文件失败");
// 验证文件内容
let content = fs::read_to_string(&file_path).expect("读取文件失败");
assert_eq!(content, "测试数据");
// 测试完成后,临时目录会自动删除
}
2. 模拟资产环境完整示例
use asset_test_utils::{AssetEnvironment, MockAsset};
#[test]
fn test_config_loading() {
// 创建模拟环境
let mut env = AssetEnvironment::new();
// 添加多个模拟资产
env.add_asset(MockAsset::new(
"config.toml",
r#"
[database]
url = "postgres://localhost"
user = "admin"
"#
));
env.add_asset(MockAsset::new(
"settings.json",
r#"{"timeout": 30}"#
));
// 获取并验证配置
let config = env.get_asset("config.toml").unwrap();
assert!(config.contains("postgres://localhost"));
let settings = env.get_asset("settings.json").unwrap();
assert!(settings.contains("\"timeout\": 30"));
}
3. 数据库测试完整示例
use asset_test_utils::TestDatabase;
use sqlx::{PgPool, Row};
#[tokio::test]
async fn test_user_operations() {
// 初始化测试数据库
let db = TestDatabase::new("postgres://postgres@localhost/test_db")
.expect("数据库初始化失败");
// 获取数据库连接池
let pool = db.pool().await;
// 创建测试表
sqlx::query(
"CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT, email TEXT)"
)
.execute(&pool)
.await
.expect("创建表失败");
// 插入测试数据
sqlx::query(
"INSERT INTO users (name, email) VALUES ($1, $2)"
)
.bind("Alice")
.bind("alice@example.com")
.execute(&pool)
.await
.expect("插入数据失败");
// 查询验证
let row = sqlx::query("SELECT * FROM users WHERE name = $1")
.bind("Alice")
.fetch_one(&pool)
.await
.expect("查询失败");
assert_eq!(row.get::<String, _>("email"), "alice@example.com");
// 测试完成后数据库会自动清理
}
4. 共享资源完整示例
use asset_test_utils::SharedTestResource;
use lazy_static::lazy_static;
lazy_static! {
static ref SHARED_DATA: SharedTestResource<String> = SharedTestResource::new(|| {
// 模拟昂贵的初始化过程
println!("初始化共享资源...");
String::from("共享数据")
});
}
#[test]
fn test_shared_resource_1() {
let data = SHARED_DATA.get();
assert_eq!(data, "共享数据");
}
#[test]
fn test_shared_resource_2() {
let data = SHARED_DATA.get();
assert!(!data.is_empty());
}
5. 自定义资源完整示例
use asset_test_utils::{TestResource, ResourceCleanup};
use std::sync::atomic::{AtomicBool, Ordering};
struct CustomService {
active: AtomicBool,
}
impl CustomService {
fn new() -> Self {
println!("启动自定义服务...");
CustomService {
active: AtomicBool::new(true)
}
}
fn perform_action(&self) -> bool {
self.active.load(Ordering::SeqCst)
}
}
impl ResourceCleanup for CustomService {
fn cleanup(&mut self) {
println!("关闭自定义服务...");
self.active.store(false, Ordering::SeqCst);
}
}
#[test]
fn test_custom_service() {
let service = TestResource::new(CustomService::new());
// 使用自定义服务
assert!(service.perform_action());
// 测试完成后会自动调用cleanup()
}
最佳实践
- 对于需要文件系统操作的测试,优先使用
TempDir
而不是手动创建/删除文件 - 对于数据库测试,使用
TestDatabase
确保每次测试都有干净的环境 - 对于昂贵的资源初始化,考虑使用
SharedTestResource
跨测试共享 - 在测试失败时检查资源状态,
asset-test-utils
会保留失败测试的资源以便调试
注意事项
- 确保测试是并行安全的,特别是使用共享资源时
- 避免在测试中硬编码路径,始终使用库提供的路径方法
- 对于大型测试集,注意资源清理的性能影响
通过使用asset-test-utils
,你可以更专注于测试逻辑本身,而不必担心测试资源的生命周期管理问题。