Rust测试实战:错误处理、环境变量与模拟服务器
立即解锁
发布时间: 2025-09-05 00:59:04 阅读量: 11 订阅数: 61 AIGC 


Rust Web开发实战
# Rust 测试实战:错误处理、环境变量与模拟服务器
在 Rust 开发中,测试是确保代码质量和稳定性的关键环节。本文将深入探讨 Rust 中的测试技巧,包括错误处理、环境变量的使用以及如何创建模拟服务器来进行测试。
## 1. 错误处理与比较
在 Rust 中,我们可以为自定义错误类型实现 `std::fmt::Display` 特征,以便将错误信息转换为字符串。以下是一个示例:
```rust
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match &*self {
Error::ParseError(ref err) => write!(f, "Cannot parse parameter: {}", err),
Error::MissingParameters => write!(f, "Missing parameter"),
Error::WrongPassword => write!(f, "Wrong password"),
Error::CannotDecryptToken => write!(f, "Cannot decrypt error"),
Error::Unauthorized => write!(f, "No permission to change the underlying resource"),
Error::ArgonLibraryError(_) => write!(f, "Cannot verifiy password"),
Error::DatabaseQueryError(_) => write!(f, "Cannot update, invalid data"),
Error::MigrationError(_) => write!(f, "Cannot migrate data"),
Error::ReqwestAPIError(err) => write!(f, "External API error: {}", err),
Error::MiddlewareReqwestAPIError(err) => write!(f, "External API error: {}", err),
Error::ClientError(err) => write!(f, "External Client error: {}", err),
Error::ServerError(err) => write!(f, "External Server error: {}", err),
}
}
}
```
通过实现 `Display` 特征,我们可以使用 `format!` 宏将错误信息转换为字符串,方便进行比较。例如:
```rust
let pagination_result = format!("{}", extract_pagination(params).unwrap_err());
let expected = format!("{}", Error::MissingParameters);
assert_eq!(pagination_result, expected);
```
由于字符串实现了 `PartialEq` 特征,因此可以在 `assert_eq!` 宏中使用。此外,标准库中的错误类型还实现了 `kind()` 函数,可以用于获取错误的类型并进行比较。
## 2. 使用环境变量测试 Config 模块
在 Rust 中,默认情况下所有测试都是并行运行的,这虽然提高了性能和速度,但可能会引入副作用。在测试 `Config` 模块时,我们会遇到设置和移除环境变量对其他测试产生影响的问题。
### 2.1 Config 模块的实现
`Config` 模块的 `new` 函数会检查环境变量 `BAD_WORDS_API_KEY` 和 `PASETO_KEY` 是否设置,如果未设置则会触发 `panic`。以下是 `Config` 模块的部分实现:
```rust
impl Config {
pub fn new() -> Result<Config, handle_errors::Error> {
dotenv::dotenv().ok();
let config = Config::parse();
if let Err(_) = env::var("BAD_WORDS_API_KEY") {
panic!("BadWords API key not set");
}
if let Err(_) = env::var("PASETO_KEY") {
panic!("PASETO_KEY not set");
}
// ...
}
}
```
为了避免每次调用 `new` 函数时都设置环境变量,我们将 `dotenv::dotenv().ok()` 调用移到 `main` 函数中,使 `new` 函数成为无副作用的函数。
### 2.2 编写测试用例
我们在 `config.rs` 文件的末尾添加测试模块,编写测试用例来验证 `Config` 模块的行为。
```rust
#[cfg(test)]
mod config_tests {
use super::*;
#[test]
fn unset_api_key() {
let result = std::panic::catch_unwind(|| Config::new());
assert!(result.is_err());
}
}
```
在这个测试用例中,我们使用 `std::panic::catch_unwind` 函数捕获 `panic`,并通过 `assert!(result.is_err())` 检查 `Config::new()` 是否出错。
### 2.3 处理环境变量的影响
当我们添加一个测试用例来验证设置环境变量后 `Config` 模块是否能正常工作时,会发现之前的测试用例可能会失败。这是因为 Rust 测试是并行运行的,设置环境变量会影响其他测试。
```rust
#[cfg(test)]
mod config_tests {
use super::*;
fn set_env() {
env::set_var("BAD_WORDS_API_KEY", "yes");
env::set_var("PASETO_KEY", "yes");
env::set_var("POSTGRES_USER", "user");
env::set_var("POSTGRES_PASSWORD", "pass");
env::set_var("POSTGRES_HOST", "localhost");
env::set_var("POSTGRES_PORT", "5432");
env::set_var("POSTGRES_DB", "rustwebdev");
}
#[test]
fn unset_api_key() {
let result = std::panic::catch_unwind(|| Config::new());
assert!(result.is_err());
}
#[test]
fn set_api_key() {
set_env();
let expected = Config {
log_level: "warn".to_string(),
port: 8080,
db_user: "user".to_string(),
db_password: "pass".to_string(),
db_host: "localhost".to_string(),
db_port: 5432,
db_name: "rustwebdev".to_string(),
};
let config = Config::new().unwrap();
assert_eq!(config, expected);
}
}
```
为了解决这个问题,我们可以将两个测试用例合并为一个,确保先测试未设置环境变量的情况,再测试设置环境变量的情况。
```rust
#[test]
fn unset_and_set_api_key() {
// ENV VARIABLES ARE NOT SET
let result = std::panic::catch_unwind(|| Config::new());
assert!(result.is_err());
// NOW WE SET THEM
set_env();
let expected = Config {
log_level: "warn".to_string(),
port: 8080,
db_user: "user".to_string(),
```
0
0
复制全文
相关推荐









