Rust测试辅助库test-with的使用:简化单元测试与集成测试的编写与执行
Rust测试辅助库test-with的使用:简化单元测试与集成测试的编写与执行
test-with是一个帮助你在特定条件下运行测试的库,如果条件不满足则会清晰地显示忽略信息。它还能让你更轻松地使用自定义测试环境或模拟服务运行测试。
安装
在项目的dev-dependencies中添加:
[dev-dependencies]
test-with = "*"
如果要减少依赖大小和编译时间,可以禁用默认功能并只启用特定功能:
[dev-dependencies]
test-with = { version = "*", default-features = false, features = ["http"] }
可用功能包括:net
(http
, icmp
), resource
, user
, executable
。
环境变量测试
// PWD环境变量存在时运行测试
#[test_with::env(PWD)]
#[test]
fn test_works() {
assert!(true);
}
// NOTHING环境变量不存在时运行测试
#[test_with::env(NOTHING)]
#[test]
fn test_ignored() {
panic!("should be ignored")
}
完整示例:
#[test_with::env(PWD)]
#[test]
fn test_with_env_var() {
// 这个测试只会在PWD环境变量存在时运行
assert!(true);
}
#[test_with::no_env(GITHUB_ACTIONS)]
#[test]
fn test_ignore_in_github_action() {
// 这个测试在GITHUB_ACTIONS环境变量存在时会被忽略
println!("Should be ignored in GITHUB_ACTION");
}
文件/文件夹测试
// /etc/hostname文件存在时运行测试
#[test_with::file(/etc/hostname)]
#[test]
fn test_works() {
assert!(true);
}
// /etc/nothing文件不存在时运行测试
#[test_with::file(/etc/nothing)]
#[test]
fn test_ignored() {
panic!("should be ignored")
}
// /etc目录存在时运行测试
#[test_with::path(/etc)]
#[test]
fn test_works_for_path() {
assert!(true);
}
完整示例:
#[test_with::file(Cargo.toml)]
#[test]
fn test_with_file() {
// 这个测试只会在Cargo.toml文件存在时运行
assert!(true);
}
#[test_with::path(src)]
#[test]
fn test_with_directory() {
// 这个测试只会在src目录存在时运行
assert!(true);
}
HTTP/HTTPS服务测试
// https服务存在时运行测试
#[test_with::https(www.rust-lang.org)]
#[test]
fn test_works() {
assert!(true);
}
// not.exist.com不存在时运行测试
#[test_with::https(not.exist.com)]
#[test]
fn test_ignored() {
panic!("should be ignored")
}
完整示例:
#[test_with::http(localhost:8080)]
#[test]
fn test_with_http_service() {
// 这个测试只会在localhost:8080 HTTP服务可用时运行
assert!(true);
}
#[test_with::https(api.example.com)]
#[test]
fn test_with_https_service() {
// 这个测试只会在api.example.com HTTPS服务可用时运行
assert!(true);
}
TCP套接字测试
// TCP端口53可用时运行测试
#[test_with::tcp(8.8.8.8:53)]
#[test]
fn test_works() {
assert!(true);
}
// 193.194.195.196不可用时运行测试
#[test_with::tcp(193.194.195.196)]
#[test]
fn test_ignored() {
panic!("should be ignored")
}
完整示例:
#[test_with::tcp(127.0.0.1:6379)]
#[test]
fn test_with_redis() {
// 这个测试只会在本地Redis服务(6379端口)可用时运行
assert!(true);
}
运行时测试
启用runtime功能:
test-with = { version = "0.15.0", features = ["runtime"] }
libtest-with = { version = "0.8.1-10", features = ["net", "resource", "user", "executable"] }
示例:
test_with::runner!(module_name);
#[test_with::module]
mod module_name {
#[test_with::runtime_env(PWD)]
fn test_works() {
}
}
完整示例:
test_with::runner!(custom_mod);
fn something_happened() -> Option<String> {
Some("because something happened".to_string())
}
#[test_with::module]
mod custom_mod {
#[test_with::runtime_ignore_if(something_happened)]
fn test_ignored() {
assert!(false);
}
}
锁测试
// 使用文件锁确保测试顺序执行
#[test_with::lock(LOCK)]
fn test_1() {
assert!(true);
}
#[test_with::lock(LOCK)]
fn test_2() {
assert!(true);
}
完整示例:
#[test_with::lock(DATABASE_LOCK, 10)] // 10秒等待时间
#[test]
fn test_database_operation1() {
// 这个测试会获取DATABASE_LOCK锁
assert!(true);
}
#[test_with::lock(DATABASE_LOCK, 10)]
#[test]
fn test_database_operation2() {
// 这个测试会等待前一个测试释放锁
assert!(true);
}
时区测试
// UTC时区运行测试
#[test_with::timezone(0)]
#[test]
fn test_works() {
assert!(true);
}
// GMT+8时区运行测试
#[test_with::timezone(+8)]
#[test]
fn test_run_in_TW() {
assert!(true)
}
完整示例:
#[test_with::timezone(+8)]
#[test]
fn test_in_taiwan_timezone() {
// 这个测试只会在GMT+8时区运行
assert!(true);
}
用户/组条件测试
#[test_with::root()]
#[test]
fn test_ignored() {
panic!("should be ignored")
}
#[test_with::group(avengers)]
#[test]
fn test_ignored2() {
panic!("should be ignored")
}
#[test_with::user(spider)]
#[test]
fn test_ignored3() {
panic!("should be ignored")
}
完整示例:
#[test_with::user(admin)]
#[test]
fn test_admin_only() {
// 这个测试只会在admin用户下运行
assert!(true);
}
可执行文件测试
// `pwd`命令存在时运行测试
#[test_with::executable(pwd)]
#[test]
fn test_executable() {
assert!(true);
}
// `/bin/sh`存在时运行测试
#[test_with::executable(/bin/sh)]
#[test]
fn test_executable_with_path() {
assert!(true);
}
完整示例:
#[test_with::executable(docker)]
#[test]
fn test_with_docker() {
// 这个测试只会在docker命令可用时运行
assert!(true);
}
test-with库提供了多种条件测试方式,可以大大简化Rust项目中单元测试和集成测试的编写与执行,特别是在需要特定环境或依赖服务的测试场景中。
1 回复
Rust测试辅助库test-with的使用:简化单元测试与集成测试的编写与执行
test-with
是一个Rust测试辅助库,旨在简化单元测试和集成测试的编写与执行过程。它提供了一些实用功能来管理测试环境、处理测试数据以及控制测试执行流程。
主要特性
- 简化测试函数的编写
- 支持测试环境设置和清理
- 提供参数化测试支持
- 改进测试输出和报告
安装方法
在Cargo.toml中添加依赖:
[dev-dependencies]
test-with = "0.1"
基本使用方法
简单测试示例
use test_with::test_with;
#[test_with]
fn test_addition() {
assert_eq!(2 + 2, 4);
}
带环境的测试
use test_with::test_with;
struct TestEnv {
value: i32,
}
#[test_with(setup = setup_env, teardown = teardown_env)]
fn test_with_environment() {
let env = TestEnv::current();
assert_eq!(env.value, 42);
}
fn setup_env() -> TestEnv {
TestEnv { value: 42 }
}
fn teardown_env(env: TestEnv) {
// 清理资源
}
参数化测试
use test_with::test_with;
#[test_with(params = [1, 2, 3, 4])]
fn test_even_numbers(param: i32) {
assert_eq!(param % 2, 0);
}
异步测试支持
use test_with::test_with;
use tokio::runtime::Runtime;
#[test_with(runtime = Runtime::new().unwrap())]
async fn test_async_function() {
let result = some_async_function().await;
assert!(result.is_ok());
}
测试分组
use test_with::{test_with, TestGroup};
#[test_with(group = "database")]
fn test_db_connection() {
// 测试数据库连接
}
#[test_with(group = "database")]
fn test_db_query() {
// 测试数据库查询
}
// 可以只运行特定分组的测试
// cargo test -- --group database
高级功能
测试依赖
use test_with::test_with;
#[test_with(depends = ["setup_data"])]
fn test_using_data() {
// 这个测试会在setup_data测试完成后运行
}
#[test_with]
fn setup_data() {
// 准备测试数据
}
条件测试
use test_with::test_with;
#[test_with(skip_if = cfg!(windows))]
fn test_unix_only() {
// 这个测试不会在Windows上运行
}
配置选项
可以在项目根目录下创建test-with.toml
文件来配置全局测试行为:
[default]
timeout = 30 # 默认测试超时时间(秒)
report = "detailed" # 测试报告格式
完整示例demo
下面是一个结合多个功能的完整示例:
// 引入test-with宏
use test_with::{test_with, TestGroup};
use tokio::runtime::Runtime;
// 测试环境结构体
struct DatabaseTestEnv {
connection_string: String,
connected: bool,
}
// 简单测试示例
#[test_with]
fn test_simple_math() {
assert_eq!(3 * 3, 9);
}
// 带环境的测试
#[test_with(setup = setup_db_env, teardown = teardown_db_env)]
fn test_database_connection() {
let env = DatabaseTestEnv::current();
assert!(env.connected);
assert!(!env.connection_string.is_empty());
}
fn setup_db_env() -> DatabaseTestEnv {
DatabaseTestEnv {
connection_string: "test_db://localhost".to_string(),
connected: true,
}
}
fn teardown_db_env(env: DatabaseTestEnv) {
println!("清理数据库连接: {}", env.connection_string);
}
// 参数化测试
#[test_with(params = [2, 4, 6, 8])]
fn test_even_numbers(param: i32) {
assert_eq!(param % 2, 0);
}
// 异步测试
#[test_with(runtime = Runtime::new().unwrap())]
async fn test_async_operation() {
let result = async { Ok::<_, String>(42) }.await;
assert_eq!(result.unwrap(), 42);
}
// 测试分组
#[test_with(group = "database")]
fn test_db_query() {
// 模拟数据库查询测试
assert!(true);
}
// 测试依赖
#[test_with]
fn setup_test_data() {
println!("准备测试数据");
}
#[test_with(depends = ["setup_test_data"])]
fn test_using_prepared_data() {
println!("使用预先准备的数据进行测试");
}
// 条件测试
#[test_with(skip_if = cfg!(windows))]
fn test_linux_specific_feature() {
// 这个测试不会在Windows上运行
println!("测试Linux特有功能");
}
这个完整示例展示了test-with
库的主要功能:
- 简单测试
- 带环境设置和清理的测试
- 参数化测试
- 异步测试支持
- 测试分组
- 测试依赖管理
- 条件测试
要运行这些测试,只需执行常规的cargo test
命令,或者使用cargo test -- --group database
来只运行特定分组的测试。