rust - 用于测试的抽象操作系统环境变量
问题描述
我创建了一个Server
结构,它由 2 个端口、一个 IP 地址和一个端口组成。无法指定分配给端口的值,但它是从系统的环境变量中读取的。当未找到环境变量或它不是有效值时,它默认为标准端口。
struct Server {
ip: String,
port: u16,
}
impl Server {
const STD_PORT: u16 = 4333;
const PORT_ENV_VAR: &'static str = "MEMDB_PORT";
fn new(ip: String) -> Server {
Server {
ip: ip,
port: Server::get_port(),
}
}
fn get_port() -> u16 {
match env::var(Server::PORT_ENV_VAR) {
Ok(val) => match val.parse::<u16>() {
Ok(val) => val,
Err(_) => Server::STD_PORT,
},
Err(_) => Server::STD_PORT,
}
}
}
当我想为它创建测试时,可以通过以下方式完成:
#[cfg(test)]
mod tests {
use crate::Server;
#[test]
fn test_create_server_assigns_correct_ip() {
// WHEN:
let server = crate::Server::new("127.0.0.1".to_owned());
// THEN:
assert_eq!(server.ip, "127.0.0.1");
}
#[test]
fn test_create_server_assigns_correct_port() {
// WHEN:
let server = crate::Server::new("".to_owned());
// THEN:
assert_eq!(server.port, 4333);
}
}
当然,当环境变量MEMDB_PORT
被赋值时,这个测试会产生不同的结果。
我如何能够通过设置正确的环境变量来验证分配的端口是否可以控制?
我正在考虑创建一个特征来定义 API 以访问系统的环境变量。
trait EnvironmentReader {
fn get(key: &str) -> Option<String>;
}
struct OSEnvironmentReader {}
impl EnvironmentReader for OSEnvironmentReader {
fn get(key: &str) -> Option<String> {
return match env::var(key) {
Ok(val) => Some(val),
Err(_) => None,
};
}
}
这是如何在 Rust 中做到这一点的正确方法吗?如果是这样,我应该如何修改我的结构来使用这个特性?将它作为一个字段添加到结构本身,我如何使用新的“dyn”东西来做到这一点?
解决方案
这里不需要dyn
或特征。只需创建一个配置结构:
pub struct ServerConfig {
pub port: u16,
}
impl ServerConfig {
const STD_PORT: u16 = 4333;
const PORT_ENV_VAR: &'static str = "MEMDB_PORT";
fn from_environment() -> ServerConfig {
ServerConfig {
port: Self::port_from_env(),
}
}
fn port_from_env() -> u16 {
// Also shortened the `match` a bit here. Could make this generic too.
env::var(ServerConfig::PORT_ENV_VAR)
.map(|val| val.parse::<u16>())
.unwrap_or(ServerConfig::STD_PORT)
}
}
Server
然后在构建它时将其传递给您:
struct Server {
config: Config,
ip: String,
}
impl Server {
fn new(config: Config, ip: String) -> Server {
Server {
config,
ip,
}
}
}
在生产代码中,通过ServerConfig::from_environment()
. 在您的测试代码中,传递一个自定义ServerConfig { port: 4333 }
. 您仍然没有测试该端口是否正确地从环境中获取,但是在您提到的评论中您不想要它并且宁愿将其模拟出来。
如果它更适合您的设计,您也可以搬进ip
去。ServerConfig
推荐阅读
- virtual-machine - 如何使用 Host-Only Adapter 将来宾 VM 与主机通信?(虚拟盒子)
- python - 如何使用 Python 中的表格从 .docx 中提取文本
- python-2.7 - Python中的类变量和静态方法
- reactjs - 自定义挂钩重置为其初始状态
- android - 使用 Kotlinx.Serialization 和 Retrofit 反序列化响应
- r - 如何在不同的预测模型系列之间做出决定以自动预测 150 个时间序列?
- android - 未在 Android 中重建数据包时得到二进制数据
- mysql - 尽管列具有不同的数据类型,但外键被拒绝
- vert.x - Vertx 处理程序为身份验证和标头调用了两次
- docker - 错误 NETSDK1064:未找到包 DnsClient,1.2.0