Unit Testing

Test Modules

A test module is a convention in Rust where unit tests and test-only helper functions are grouped inside an inline submodule named tests annotated with #[cfg(test)] at the bottom of a source file.

src/parser.rs
+-------------------------------------------------------------------+
|  pub fn parse_header(line: &str) -> Option<(&str, &str)> { ... }  |
|  fn trim_comment(line: &str) -> &str { ... }                      |
|                                                                   |
|  #[cfg(test)]  <-- Included ONLY when compiling for tests         |
|  mod tests {                                                      |
|      use super::*;  <-- Imports everything from `parser` module   |
|                                                                   |
|      fn sample_input() -> &'static str { ... } // Helper function |
|                                                                   |
|      #[test]                                                      |
|      fn parses_key_value() { ... }                                |
|  }                                                                |
+-------------------------------------------------------------------+

Why #[cfg(test)] Is Essential on mod tests

While individual #[test] functions are automatically omitted during cargo build, any helper functions, mock structs, or use imports inside mod tests are ordinary Rust items. Without #[cfg(test)] on mod tests:

  1. The compiler spends time type-checking and compiling test helpers and mocks during normal cargo build and cargo build --release runs.
  2. The compiler emits dead_code and unused_imports warnings for use super::*; and test helper functions when building outside test mode because their only callers (#[test] functions) were stripped.
  3. Any [dev-dependencies] imported inside mod tests would fail to resolve during cargo build because dev-dependencies are only linked in test and benchmark builds.
Aspect Bare mod tests { ... } #[cfg(test)] mod tests { ... }
Compiled during cargo build? Yes (except #[test] functions) No (entire module is stripped at AST level)
Triggers unused_imports / dead_code warnings? Yes, on helpers and use super::*; No
Can import [dev-dependencies] crates? Fails cargo build Yes

Sharing Test Helpers and Fixtures Inside mod tests

Any function inside #[cfg(test)] mod tests that is not marked with #[test] acts as a reusable fixture or assertion helper for the tests in that module:

#[derive(Debug, PartialEq, Eq)]
pub struct Header<'a> {
    pub key: &'a str,
    pub value: &'a str,
}

pub fn parse_header(line: &str) -> Option<Header<'_>> {
    let (k, v) = line.split_once(':')?;
    let key = k.trim();
    if key.is_empty() {
        return None;
    }
    Some(Header {
        key,
        value: v.trim(),
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    // Test-only helper (no `#[test]` attribute, so not run as a standalone test)
    fn assert_header(raw: &str, expected_key: &str, expected_val: &str) {
        assert_eq!(
            parse_header(raw),
            Some(Header {
                key: expected_key,
                value: expected_val,
            })
        );
    }

    #[test]
    fn parses_standard_http_headers() {
        assert_header("Content-Type: application/json", "Content-Type", "application/json");
        assert_header("X-Request-Id :  abc-123 ", "X-Request-Id", "abc-123");
    }

    #[test]
    fn rejects_malformed_headers() {
        assert_eq!(parse_header("NoColonHere"), None);
        assert_eq!(parse_header("   : value_without_key"), None);
    }
}

fn main() {
    println!("Parsed: {:?}", parse_header("Host: example.com"));
}
Parsed: Some(Header { key: "Host", value: "example.com" })