DEV Community

Subesh Yadav
Subesh Yadav

Posted on

๐Ÿงช Day 20 of #100DaysOfRust: Writing Tests in Rust ๐Ÿฆ€

Hello, Rustaceans!
Today marks Day 20 of my #100DaysOfRust journey, and I dove into a key feature of Rust that ensures correctness and reliability โ€” writing tests.

Rust has built-in support for testing with cargo test, and it provides excellent macros, attributes, and tools for writing clear, expressive, and robust test cases.


๐Ÿงช Anatomy of a Test Function

Every test function in Rust is marked with the #[test] attribute.

A basic test function:

#[test]
fn it_works() {
    // 1. Set up any needed data or state.
    let a = 2;

    // 2. Run the code you want to test.
    let b = a + 2;

    // 3. Assert that the result is what you expect.
    assert_eq!(b, 4);
}
Enter fullscreen mode Exit fullscreen mode

โœ… Running Tests

Use this command to run all tests:

cargo test
Enter fullscreen mode Exit fullscreen mode

Rust compiles the tests in a separate test binary and shows clear output about passing or failing tests.


โœ”๏ธ Checking Conditions with assert!

The assert! macro ensures that a boolean condition is true. If it's not, the test fails.

#[test]
fn assert_macro_example() {
    let value = true;
    assert!(value); // Passes
}
Enter fullscreen mode Exit fullscreen mode

Fails if:

assert!(false); // panics with default message
Enter fullscreen mode Exit fullscreen mode

You can also add a custom failure message:

assert!(1 + 1 == 3, "Math is broken!");
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฎ Testing Equality with assert_eq! and assert_ne!

Rust provides macros to compare values:

  • assert_eq!(a, b) โ€” passes if a == b
  • assert_ne!(a, b) โ€” passes if a != b
#[test]
fn test_equality_macros() {
    assert_eq!(2 + 2, 4);
    assert_ne!(5, 3);
}
Enter fullscreen mode Exit fullscreen mode

When these fail, Rust shows both the expected and actual values, making debugging easier.


๐Ÿ’ฌ Custom Failure Messages

You can also include custom messages in these macros:

#[test]
fn custom_message_example() {
    let result = 2 + 2;
    assert_eq!(result, 5, "Expected 5 but got {}", result);
}
Enter fullscreen mode Exit fullscreen mode

Output:

thread 'main' panicked at 'Expected 5 but got 4', src/main.rs:4:5
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ฅ Testing for Panics with #[should_panic]

Some tests are expected to panic (i.e., crash intentionally under specific conditions).

Use the #[should_panic] attribute:

#[test]
#[should_panic]
fn panics_when_called() {
    panic!("This function panics!");
}
Enter fullscreen mode Exit fullscreen mode

Make it more precise using expected:

#[test]
#[should_panic(expected = "Guess value must be less than or equal to 100")]
fn panic_with_message() {
    panic!("Guess value must be less than or equal to 100");
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Writing Tests That Return Result<T, E>

Rust lets you write tests that return Result<(), E> for clearer error reporting.

#[test]
fn test_with_result() -> Result<(), String> {
    let value = 2 + 2;

    if value == 4 {
        Ok(())
    } else {
        Err("2 + 2 did not equal 4".into())
    }
}
Enter fullscreen mode Exit fullscreen mode

This lets you use ? inside your tests, which is especially useful when testing functions that return Result.


๐Ÿงช Summary

Concept Description
#[test] Marks a function as a unit test
assert!, assert_eq!, assert_ne! Macros to validate test conditions
#[should_panic] Use when a function should panic
Result<(), E> return type Clean test error reporting and ? usage
Custom messages Improve failure debugging

๐Ÿ—•๏ธ Whatโ€™s Next?

In Day 21, Iโ€™ll explore how to organize tests, including modules, integration tests, test hierarchies, and best practices.

Let me know your favorite testing tip in Rust!
Until tomorrow, happy coding! ๐Ÿฆ€

Top comments (0)