Trusted answers to developer questions
Trusted Answers to Developer Questions

Related Tags

rust

How to write test functions in Rust

Educative Team

Overview

In the Rust programming language, we use test functions to test the non-test code in a program.

We can use a test function using three main steps:

  • We include any data that we need for the respective code.
  • We include and run the code for which we write the test case.
  • We write the test by asserting the values or results that we expect.

Writing test cases can help us find if any part of the code is working or not.

To write a test function, it is necessary to add an attribute #[test] before the start of the test function. Rust creates a binary file for the piece of code that includes the #[test] annotation.

#[test]
 fn success(){
      //The body of the test function
 }
Syntax to write a test function

Creating test functions

To test the code, we can write multiple test cases. We can run a test case by using the following command:

cargo test

The cargo test command executes the test functions that we write.

Example

Let’s write our own test function with the help of an example project.

  1. We create a project using the following command:
cargo new project

The new command creates a new directory, project. Our project directory contains the main.rs file.

  1. We write our function in the main.rs file.
mod test;
fn check_even_num(value:i32) -> bool {
        if value % 2 == 0{
            true
        }
        else 
         { 
             false 
        }
    }
Function to check if the number is even
  1. We create a test.rs file to write the test function.
use crate::check_even_num;

#[test]
fn success(){
    assert!(check_even_num(4));
}

#[test]
fn check_failure(){
    assert_eq!(check_even_num(3),false);
}
  1. We add the module test in the main.rs file by adding the following line:
mod test;
  1. We run the following command in the root folder of our project:
cargo test

It shows the following output:

Compiling project v0.1.0 (/project)
    Finished test [unoptimized + debuginfo] target(s) in 0.50s
     Running unittests src/main.rs (/project/target/debug/deps/project-04898232a9e03d49)

running 2 tests
test test::check_failure ... ok
test test::success ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
The output of the cargo test command

We can run the cargo test command below and hit the "Run" button to see the terminal.

[package]
name = "project"
version = "0.1.0"
authors = ["Laraib"]

[dependencies]

Explanation

In the main.rs file, mod test; is added to include the test file.

In the test.rs file, we do the following:

  • Line 3: We use #[test] to specify this is a test case i.e., success() and check_failure.
  • Line 4: In the success() function, we use assert(). This passes the test if a true value is passed to it.
  • Line 9: In the check_failure() test case, assert_eq!() compares the two values and passes the test case if they match.

Testing panics and ignore attributes in test functions

We use the #[should_panic] attribute when we try to write a condition where a function should panic. One example is when we write a function for division, and we create a panic case when the user inputs zero value for the denominator.

In the scenario where we write multiple test cases, we use the #[ignore] attribute to exclude the cases we don’t want to execute.

We can understand this by looking at an example.

Example

pub fn nonZeroDivision(a: u32, b: u32) -> u32 {
    if b == 0 {
        panic!("Divide-by-zero error");
    } else if a < b {
        panic!("Divide result is zero");
    }
    a / b
}

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

    #[test]
    fn test_divide() {
        assert_eq!(nonZeroDivision(10, 2), 5);
    }

    #[test]
    #[should_panic]
    fn test_any_panic() {
        nonZeroDivision(1, 0);
    }

    #[test]
    #[should_panic(expected = "Divide result is zero")]
    fn test_specific_panic() {
        nonZeroDivision(1, 10);
    }
}

Explanation

  • Lines 1–6: We write a function to divide two values.
  • Lines 18–21: We use the should_panic keyword to throw panic when the function gets zero as the denominator value.
  • Lines 24–27: We use the [ignore] keyword before the test case. This will ignore the individual test case when running the test cases for the function.

RELATED TAGS

rust
Copyright ©2022 Educative, Inc. All rights reserved
RELATED COURSES

View all Courses

Keep Exploring