Rust时间模拟库sn_fake_clock的使用,轻松实现测试环境中的时间控制和模拟

Rust时间模拟库sn_fake_clock的使用,轻松实现测试环境中的时间控制和模拟

概述

sn_fake_clock提供了一个FakeClock结构体,它模仿了std::time::Instant的接口,并能在测试期间完全控制代码感知到的时间流。

安装

在项目目录中运行以下Cargo命令:

cargo add sn_fake_clock

或者在Cargo.toml中添加以下行:

sn_fake_clock = "0.4.14"

使用示例

下面是一个完整的示例demo,展示如何使用sn_fake_clock来模拟和控制时间:

use sn_fake_clock::FakeClock;
use std::time::Duration;

#[test]
fn test_time_control() {
    // 初始化假时钟
    FakeClock::set_time(0);
    
    // 获取当前时间
    let start = FakeClock::now();
    assert_eq!(start.elapsed(), Duration::from_secs(0));
    
    // 向前推进时间
    FakeClock::advance_time(Duration::from_secs(10));
    
    // 验证时间确实前进了
    assert_eq(start.elapsed(), Duration::from_secs(10));
    
    // 设置特定时间点
    FakeClock::set_time(100);
    assert_eq(FakeClock::now().elapsed(), Duration::from_secs(100));
}

#[test]
fn test_time_dependent_logic() {
    FakeClock::set_time(0);
    
    let start = FakeClock::now();
    
    // 模拟需要等待的逻辑
    FakeClock::advance_time(Duration::from_millis(500));
    
    // 验证经过的时间
    let elapsed = start.elapsed();
    assert!(elapsed >= Duration::from_millis(500));
    assert!(elapsed < Duration::from_millis(501));
}

完整示例

use sn_fake_clock::FakeClock;
use std::time::Duration;
use std::thread;

// 测试时间控制功能
#[test]
fn test_clock_operations() {
    // 初始化时间为0
    FakeClock::set_time(0);
    
    // 验证初始时间
    let now = FakeClock::now();
    assert_eq!(now.elapsed(), Duration::from_secs(0));
    
    // 前进5秒
    FakeClock::advance_time(Duration::from_secs(5));
    assert_eq!(now.elapsed(), Duration::from_secs(5));
    
    // 前进500毫秒
    FakeClock::advance_time(Duration::from_millis(500));
    assert_eq!(now.elapsed(), Duration::from_millis(5500));
    
    // 直接设置时间为10秒
    FakeClock::set_time(10_000);
    assert_eq!(FakeClock::now().elapsed(), Duration::from_millis(10_000));
}

// 测试时间敏感逻辑
#[test]
fn test_time_sensitive_operations() {
    FakeClock::set_time(0);
    
    // 记录开始时间
    let start = FakeClock::now();
    
    // 模拟耗时操作
    FakeClock::advance_time(Duration::from_secs(3));
    
    // 检查耗时
    assert_eq!(start.elapsed(), Duration::from_secs(3));
    
    // 模拟短时间等待
    FakeClock::advance_time(Duration::from_millis(250));
    assert_eq!(start.elapsed(), Duration::from_millis(3250));
}

// 测试定时器功能
#[test]
fn test_timer_functionality() {
    FakeClock::set_time(0);
    
    let timer_start = FakeClock::now();
    
    // 模拟定时器超时(1秒后)
    FakeClock::advance_time(Duration::from_secs(1));
    
    // 检查是否超时
    assert!(timer_start.elapsed() >= Duration::from_secs(1));
    assert!(timer_start.elapsed() < Duration::from_secs(2));
    
    // 再前进500毫秒
    FakeClock::advance_time(Duration::from_millis(500));
    assert_eq!(timer_start.elapsed(), Duration::from_millis(1500));
}

主要功能

  1. 设置特定时间点:使用FakeClock::set_time可以直接设置时钟到特定时间
  2. 前进时间:使用FakeClock::advance_time可以模拟时间的流逝
  3. 获取当前时间FakeClock::now()返回一个类似Instant的对象,可以测量时间间隔

许可证

这个SAFE Network库采用双重许可:

  • 修改后的BSD许可证
  • MIT许可证

您可以选择其中一种。

贡献

欢迎贡献!无论是编写新代码、修复bug还是报告错误,所有形式的贡献都受到鼓励。


1 回复

Rust时间模拟库sn_fake_clock使用指南

简介

sn_fake_clock是一个Rust库,专门用于在测试环境中模拟和控制时间。它允许开发者在不修改系统时间的情况下,创建可控的时间环境,这对于需要测试时间相关逻辑的应用程序特别有用。

主要特性

  • 模拟系统时间而不影响真实系统时钟
  • 支持时间跳转(向前或向后)
  • 线程安全的时间控制
  • 易于集成到现有测试框架中

安装

在Cargo.toml中添加依赖:

[dependencies]
sn_fake_clock = "0.1"

完整示例代码

下面是一个完整的测试用例,展示了sn_fake_clock的主要功能:

use sn_fake_clock::FakeClock;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

// 测试基本时间模拟功能
#[test]
fn test_fake_clock_basic() {
    // 1. 基础时间模拟
    let mut clock = FakeClock::from_millis(1609459200000); // 2021-01-01 00:00:00 UTC
    assert_eq!(clock.now_millis(), 1609459200000);
    
    // 2. 时间跳转测试
    // 向前跳转1天
    clock.advance(Duration::from_secs(86400));
    assert_eq!(clock.now_millis(), 1609459200000 + 86400*1000);
    
    // 向后跳转12小时
    clock.rewind(Duration::from_secs(43200));
    assert_eq!(clock.now_millis(), 1609459200000 + 43200*1000);
}

// 测试全局时间冻结功能
#[test]
fn test_global_time_freeze() {
    // 冻结全局时间为特定时间点
    let _guard = FakeClock::freeze_at_millis(1609459200000); // 2021-01-01 00:00:00
    
    // 获取当前时间戳的函数
    fn current_timestamp() -> u64 {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs()
    }
    
    // 验证时间是否正确冻结
    assert_eq!(current_timestamp(), 1609459200);
    
    // 全局时间跳转1小时
    FakeClock::advance(Duration::from_secs(3600));
    assert_eq!(current_timestamp(), 1609459200 + 3600);
}

// 测试自动时间递增功能
#[test]
fn test_auto_advance() {
    let mut clock = FakeClock::from_millis(1609459200000);
    
    // 设置自动递增速率:真实1秒 = 模拟1分钟
    clock.set_auto_advance_rate(60.0);
    
    let start = clock.now_millis();
    std::thread::sleep(Duration::from_secs(1));
    let end = clock.now_millis();
    
    // 验证时间是否自动增加了约60秒
    let diff = end - start;
    assert!(diff >= 60_000 && diff <= 61_000, "实际增加时间: {}ms", diff);
}

// 测试超时逻辑
#[test]
fn test_complex_timeout() {
    let _guard = FakeClock::freeze_at_millis(1609459200000);
    let start_time = 1609459200; // 2021-01-01 00:00:00
    
    // 超时检查函数
    fn is_timeout(start: u64, timeout_secs: u64) -> bool {
        let current = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs();
        current - start >= timeout_secs
    }
    
    // 测试不同时间点的超时状态
    let test_cases = vec![
        (0, false),    // 刚开始
        (59, false),   // 差1秒超时
        (60, true),    // 刚好超时
        (120, true),   // 超时很久
    ];
    
    for (advance_secs, expected) in test_cases {
        FakeClock::rewind(Duration::from_secs(3600)); // 重置时间
        FakeClock::advance(Duration::from_secs(advance_secs));
        assert_eq!(
            is_timeout(start_time, 60),
            expected,
            "前进{}秒后超时状态应为{}",
            advance_secs,
            expected
        );
    }
}

注意事项

  1. 在测试完成后,确保释放时间模拟,以免影响其他测试
  2. 对于多线程测试,确保时间操作是线程安全的
  3. 不要在生产环境中使用这个库,它仅用于测试目的

这个完整示例展示了sn_fake_clock的主要功能,包括基础时间模拟、时间跳转、全局时间冻结、自动时间递增和超时逻辑测试。你可以根据实际测试需求调整这些示例代码。

回到顶部