Rust测试环境日志库test-env-log的使用,提供高效测试日志捕获与调试工具

Rust测试环境日志库test-env-log的使用,提供高效测试日志捕获与调试工具

test-env-log是一个用于自动初始化Rust测试中日志和追踪功能的库。它解决了测试环境中日志初始化的问题,使开发者能够方便地查看测试代码输出的日志消息。

使用示例

基本用法

use test_env_log::test;

#[test]
fn it_works() {
  info!("Checking whether it still works...");
  assert_eq!(2 + 2, 4);
  info!("Looks good!");
}

选择性初始化日志

#[test_env_log::test]
fn it_still_works() {
  // 只有这个测试会初始化日志
}

异步测试支持

use test_env_log::test;

#[test(tokio::test)]
async fn it_still_works() {
  // 支持tokio异步测试
}

日志配置

默认情况下cargo test会捕获输出,只在测试失败时显示。可以通过以下方式改变这一行为:

$ cargo test -- --nocapture

使用环境变量控制日志级别:

RUST_LOG=info cargo test -- --nocapture

特性配置

该库提供两个特性:

  • log(默认启用):用于log crate的初始化
  • trace(默认禁用):用于tracing crate的初始化

完整示例代码

首先在Cargo.toml中添加依赖:

[dev-dependencies]
test-env-log = "0.2.8"
env_logger = "*"  # 如果使用log特性
tracing = {version = "0.1", default-features = false}  # 如果使用trace特性
tracing-subscriber = {version = "0.3", default-features = false, features = ["env-filter", "fmt"]}

然后编写测试代码:

use test_env_log::test;
use log::{info, error};

// 基本测试示例
#[test]
fn addition_test() {
    info!("Starting addition test");
    assert_eq!(1 + 1, 2);
    info!("Addition test passed");
}

// 失败测试示例
#[test]
fn failing_test() {
    error!("This test will fail");
    assert_eq!(1 + 1, 3);  // 故意制造失败
}

// 异步测试示例
#[test(tokio::test)]
async fn async_addition_test() {
    info!("Starting async addition test");
    let result = async { 2 + 2 }.await;
    assert_eq!(result, 4);
    info!("Async addition test passed");
}

// 选择性日志测试
#[test_env_log::test]
fn selected_logging_test() {
    info!("This test has logging initialized separately");
    assert!(true);
}

// 带日志级别的测试
#[test]
fn log_level_test() {
    debug!("This debug message may not appear");
    info!("This info message should appear");
    warn!("This warning message should appear");
    assert_eq!(3 * 3, 9);
}

运行测试时,可以使用不同日志级别查看输出:

# 显示info及以上级别日志
RUST_LOG=info cargo test -- --nocapture

# 显示debug及以上级别日志
RUST_LOG=debug cargo test -- --nocapture

# 显示特定模块的日志
RUST_LOG=my_module=info cargo test -- --nocapture

这个完整示例展示了test-env-log的各种用法,包括基本测试、异步测试、选择性日志初始化以及不同日志级别的控制。


1 回复

Rust测试环境日志库test-env-log使用指南

简介

test-env-log是一个专为Rust测试环境设计的日志捕获库,它扩展了标准库的test功能,提供了强大的日志捕获和调试能力。这个库特别适合在单元测试和集成测试中捕获和验证日志输出。

主要特性

  • 自动初始化日志系统
  • 捕获测试期间产生的所有日志
  • 支持断言日志内容
  • 与标准测试框架无缝集成
  • 支持多种日志级别

使用方法

基本安装

在Cargo.toml中添加依赖:

[dev-dependencies]
test-env-log = "0.2"

基本使用示例

#[cfg(test)]
mod tests {
    use test_env_log::test;
    use log::{info, warn};

    #[test]
    fn test_basic_logging() {
        info!("This is an info message");
        warn!("This is a warning message");
        
        // 测试会正常执行,日志会被捕获
    }
}

验证日志输出

#[cfg(test)]
mod tests {
    use test_env_log::test;
    use log::info;

    #[test]
    fn test_log_content() {
        info!("User logged in: {}", "john_doe");
        
        let logs = test_env_log::capture_logs();
        assert!(logs.iter().any(|log| log.contains("User logged in: john_doe")));
    }
}

过滤特定日志级别

#[cfg(test)]
mod tests {
    use test_env_log::test;
    use log::{debug, info, error};

    #[test]
    fn test_error_logs() {
        debug!("Debug message - not important");
        info!("Info message - somewhat important");
        error!("Error message - critical!");
        
        let error_logs = test_env_log::capture_logs()
            .into_iter()
            .filter(|log| log.starts_with("[ERROR]"))
            .collect::<Vec<_>>();
            
        assert_eq!(error_logs.len(), 1);
        assert!(error_logs[0].contains("Error message - critical!"));
    }
}

初始化自定义日志配置

#[cfg(test)]
mod tests {
    use test_env_log::{test, Config};
    use log::LevelFilter;

    #[test]
    fn test_with_custom_config() {
        let _ = test_env_log::init_with_config(
            Config::default()
                .with_default_level(LevelFilter::Debug)
                .with_capture(true)
        );
        
        // 测试代码...
    }
}

高级用法

测试失败时显示日志

#[cfg(test)]
mod tests {
    use test_env_log::test;
    use log::error;

    #[test]
    fn test_failure_with_logs() {
        error!("Something went wrong!");
        assert!(false, "Test failed intentionally to show logs");
    }
}

当测试失败时,所有捕获的日志会自动输出,帮助调试问题。

测试并行执行时的日志隔离

#[cfg(test)]
mod tests {
    use test_env_log::test;
    use log::info;

    #[test]
    fn test_parallel_1() {
        info!("Test 1 log");
        // ...
    }

    #[test]
    fn test_parallel_2() {
        info!("Test 2 log");
        // ...
    }
}

test-env-log会自动隔离并行测试的日志输出,确保不会交叉混淆。

注意事项

  1. 确保不要在非测试代码中使用test-env-log
  2. 对于性能敏感的测试,可以考虑禁用日志捕获
  3. 使用test_env_log::init_with_config(Config::default().with_capture(false))可以初始化日志但不捕获

替代方案

如果你只需要简单的日志初始化而不需要捕获功能,可以考虑使用env_logger或其他日志库。但test-env-log提供了更完整的测试专用功能。

完整示例

下面是一个完整的测试示例,展示了test-env-log的主要功能:

// 测试模块
#[cfg(test)]
mod tests {
    use test_env_log::{test, Config};
    use log::{debug, info, warn, error, LevelFilter};

    // 基本日志测试
    #[test]
    fn test_log_levels() {
        debug!("This debug message will be captured");
        info!("This info message will be captured");
        warn!("This warning message will be captured");
        error!("This error message will be captured");
        
        // 验证所有级别的日志都被捕获
        let logs = test_env_log::capture_logs();
        assert_eq!(logs.len(), 4);
    }

    // 自定义配置测试
    #[test]
    fn test_custom_config() {
        let _ = test_env_log::init_with_config(
            Config::default()
                .with_default_level(LevelFilter::Info) // 只捕获info及以上级别的日志
                .with_capture(true)
        );
        
        debug!("This debug message will NOT be captured");
        info!("This info message will be captured");
        
        let logs = test_env_log::capture_logs();
        assert_eq!(logs.len(), 1);
        assert!(logs[0].contains("info message"));
    }

    // 日志内容断言测试
    #[test]
    fn test_log_assertions() {
        info!("Transaction started: ID=12345");
        info!("Processing item: 42");
        info!("Transaction completed: ID=12345");
        
        let logs = test_env_log::capture_logs();
        
        // 验证特定日志是否存在
        assert!(logs.iter().any(|log| log.contains("Transaction started")));
        assert!(logs.iter().any(|log| log.contains("Processing item")));
        assert!(logs.iter().any(|log| log.contains("Transaction completed")));
        
        // 验证日志顺序
        assert!(logs[0].contains("started"));
        assert!(logs[2].contains("completed"));
    }

    // 错误日志专项测试
    #[test]
    fn test_error_logging() {
        info!("System starting up");
        error!("Critical failure in module X");
        warn!("Performance degradation detected");
        error!("Secondary failure in module Y");
        
        let error_logs = test_env_log::capture_logs()
            .into_iter()
            .filter(|log| log.starts_with("[ERROR]"))
            .collect::<Vec<_>>();
            
        assert_eq!(error_logs.len(), 2);
        assert!(error_logs[0].contains("Critical failure"));
        assert!(error_logs[1].contains("Secondary failure"));
    }

    // 测试失败时的日志输出
    #[test]
    fn test_failure_log_display() {
        info!("Preparing test data");
        warn!("Potential issue detected");
        error!("Test is about to fail");
        
        // 故意让测试失败以查看日志
        assert!(false, "This test is expected to fail to demonstrate log output");
    }
}

这个库特别适合需要验证日志输出或调试复杂测试场景的情况,能显著提高测试开发和调试的效率。

回到顶部