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展示了:

  1. 如何创建自定义资产类型
  2. 如何配置不同的加载行为
  3. 如何模拟错误场景
  4. 如何测试资产依赖关系
  5. 完整的工作流程演示

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()
}

最佳实践

  1. 对于需要文件系统操作的测试,优先使用TempDir而不是手动创建/删除文件
  2. 对于数据库测试,使用TestDatabase确保每次测试都有干净的环境
  3. 对于昂贵的资源初始化,考虑使用SharedTestResource跨测试共享
  4. 在测试失败时检查资源状态,asset-test-utils会保留失败测试的资源以便调试

注意事项

  • 确保测试是并行安全的,特别是使用共享资源时
  • 避免在测试中硬编码路径,始终使用库提供的路径方法
  • 对于大型测试集,注意资源清理的性能影响

通过使用asset-test-utils,你可以更专注于测试逻辑本身,而不必担心测试资源的生命周期管理问题。

回到顶部