I have created a Server struct which consists out of 2 ports, an IP address and a port.
The value assigned to the port could NOT be specified, but it's read from the system's environment variables. When the environment variable has not been found, or when it's not a valid value, it defaults to a standard port.
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,
}
}
}
When I want to create tests for it, it can be done in the following way:
#[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);
}
}
Off course, this test produces a different result when the environment variable MEMDB_PORT has a value assigned.
How would I be able to verify that the assigned port can be controlled by setting the correct environment variable?
I was thinking about creating a trait that defined the API to access the system's environment variables.
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,
};
}
}
Is this the correct way on how to do it in Rust? If so, how should I modify my struct to use this trait? Add it as a field to the struct itself, and how can I do this with the new 'dyn' stuff?