ProgramGuru

Tests, boundaries and debugging

Tests, boundaries and debugging

A target-checking function should work at the boundary, not only for an easy passing mark. Rust’s test harness lets you encode expected behavior. A useful test describes a policy or error path rather than merely repeating each statement of the implementation.

What you’ll learn

  • Test both sides of the target and valid-range boundaries.
  • Distinguish program execution, tests and diagnostic output.

Tests, boundaries and debugging in action

  1. 74: below threshold

    The ordinary executable prints the boundary decision for 75.

    74: below threshold
  2. 75 and 100: valid target

    The test build separately runs four assertions: just below the threshold, at the threshold, at the valid maximum and above it.

    75 and 100: valid target
  3. 101: invalid mark

    The last assertion prevents treating invalid large marks as valid passes.

    101: invalid mark
The ordinary executable prints the boundary decision for 75. The test build separately runs four assertions: just below the threshold, at the threshold, at the valid maximum and above it. The last assertion prevents treating invalid large marks as valid passes.

Tests, boundaries and debugging explained

#[test] marks a test function. assert! checks a Boolean, and assert_eq! compares values. A cfg(test) module is included for test builds. Run cargo test, or rustc --edition=2024 --test main.rs -o school-tests and launch the test executable for this standalone file.

Work through the Rust program

Save the complete source as main.rs in the Rust environment. No standard input is needed.

Rust 2024 · complete program

fn meets_target(score: u32) -> bool { (75..=100).contains(&score) }
fn main() { println!("Target at 75: {}", meets_target(75)); }
#[cfg(test)]
mod tests {
  use super::meets_target;
  #[test]
  fn target_boundaries() {
    assert!(!meets_target(74));
    assert!(meets_target(75));
    assert!(meets_target(100));
    assert!(!meets_target(101));
  }
}

Expected output

Target at 75: true

Follow the execution

The ordinary executable prints the boundary decision for 75. The test build separately runs four assertions: just below the threshold, at the threshold, at the valid maximum and above it. The last assertion prevents treating invalid large marks as valid passes.

Try the complete program in the Rust compiler. For tests, Cargo commands and local files, use the specified local environment.

Try a small variation

Your task: Why include the test for 101 rather than testing only 80?

Rust 2024 · complete program

fn meets_target(score: u32) -> bool { (75..=100).contains(&score) }
fn main() { println!("Target at 75: {}", meets_target(75)); }
#[cfg(test)]
mod tests {
  use super::meets_target;
  #[test]
  fn target_boundaries() {
    assert!(!meets_target(74));
    assert!(meets_target(75));
    assert!(meets_target(100));
    assert!(!meets_target(101));
  }
}

Worked answer

It checks that the valid mark range has an upper boundary. A function using only score >= 75 would pass the easy case while incorrectly accepting 101.

Mistakes and limits to recognize

Dbg! writes a diagnostic representation to stderr and returns its expression’s value; it is not a replacement for tests. Integration tests can exercise public APIs, and documentation examples can be tested too. Nondeterministic services need controlled test inputs and explicit expectations.

Check your understanding

Why include the test for 101 rather than testing only 80?
Choose one answer. You can try again.

Answer and explanation

It checks that the valid mark range has an upper boundary.

It checks that the valid mark range has an upper boundary. A function using only score >= 75 would pass the easy case while incorrectly accepting 101.

Take the idea into your next program

It checks that the valid mark range has an upper boundary. A function using only score >= 75 would pass the easy case while incorrectly accepting 101. Dbg! writes a diagnostic representation to stderr and returns its expression’s value; it is not a replacement for tests.

Further reading: the official Rust Book on tests, boundaries and debugging.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Macros and repeated syntax →