RemoteState company logoHome

RustLLC

Testing Rust Applications

Posted On : Jun 26, 2023Author : Atul Bhatt
RustLLC

Essence of Software Testing

Software grows. In order to not sacrifice quality as the software grows, we need rigorous software testing.

Regression

There's a chance that the new code you wrote introduced defects in the system, this is called regression. If your codebase doesn't have high automation coverage than these defects could take a lot of time to be discovered and it will take even more time to detect which code changes introduced the defect.

Types of testing

Unit testing

'Unit' refers to a small isolated part of a program. It could be an individual function of a module or method of an object. Unit tests rely on mocking/stubbing(fake implementaitons). If your unit of code relies on external code, then you can "mock" that code so you can focus on testing the logic of the function.

Integration Testing

'Integration" testing is done on a component or a service of an application. A component or service can be a set of classes, methods or functions.

UI Testing

Applications are designed for "Users". User Interface testing is used to interact with UI elements and see if these elements behave as expected.

Testing in Rust

Rust provides a build-in framework for testing. Add ``#[test]` attribute to your test function and `cargo test`` will detect and execute your tests.

There are three ways of writing tests in Rust -

  • Embedded test module
  • External test folder
  • Doc tests

This is the library we will be testing. It has two private and one public API.

pub fn positive_prime(num: i32) -> bool {
  if is_positive(num) {
    return is_prime(num);
  }
  false
}

fn is_positive(num: i32) -> bool {
  if num > 0 {
    return true;
  }
  false
}

fn is_prime(num: i32) -> bool {
    for i in 2..num/2 {
        if num % i == 0 {
            return false
        }
    }
    true
}

Embedded test module

Embedded tests modules are a part the module you are testing. By adding ``#[cfg(test)]`` annotation, you can specify testing part of your module. Embedded test modules are used for unit testing because they have access to all the private structs, enums, fields, and functions. Here's an example of how you can write test for an function that tests prime numbers -

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

  #[test]
  fn test_prime_number() {
    let test_set = vec![
      (2, true),
      (6, false),
      (17, true),
      (25, false)
    ];
    
    for (num, actual) in test_set {
      let result = is_prime(num);
      assert_eq!(actual, result);
    }
  }                                                         
}
cargo test Compiling my_test_app v0.1.0 (my_test_app) Finished test [unoptimized + debuginfo] target(s) in 0.58s Running unittests src\main.rs (target\debug\deps\my_test_app-3e8a404ff158ea59.exe) running 1 test test tests::test_prime_number ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

External tests folder

Tests written in External tests folder unlike module tests, only have access to public API, much like your code being used as a dependency. External test folders are used for writing integration tests. Here's an example of testing a public API ``positive_prime` which uses two private functions `is_positive` and `is_prime``.

extern crate my_test_app;

#[test]
fn check_positive_prime() {
    let test_cases = vec![
        (2, true),
        (-2, false),
        (15, false),
        (17, true),
        (-1, false),
    ];
    for (num, actual) in test_cases {
        let result = my_test_app::positive_prime(num);
        assert_eq!(actual, result);
    }
}
cargo test --test '*' Finished test [unoptimized + debuginfo] target(s) in 0.00s Running tests\integration.rs (target\debug\deps\integration-c6e95b0ecf5394d0.exe) running 1 test test check_positive_prime ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Doc tests

Examples written in documentation need to be tested as well. Often the documentation contains deprecated piece of code that doesn't work as expectred anymore. Rust allows wrting tests in documentation. Using triple backticks, you can write executatable code in documentaion.

/// Checks whether a number is positive
/// 

/// use my_test_app::is_positive; /// is_positive(1) == true; ///

pub fn is_positive(num: i32) -> bool { if num > 0 { return true; } false } cargo test --doc is_positive Finished test [unoptimized + debuginfo] target(s) in 0.00s Doc-tests my_test_app running 1 test test src\lib.rs - is_positive (line 9) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s

Software grows. In order to not sacrifice quality as the software grows, we need rigorous software testing.

Ready to Collaborate?

We’ll respond within one business day. Connect to plan a solution that advances your product and business.

Email Us Logo

Email Us

gtm@remotestate.com

Call Us Logo

Call Us

USA: +1 - 210 972 5958

India: +91 - 977 676 7574

Our Offices Logo

Our Offices

USA - 2219 Main Street, Santa Monica, CA 90405

India - Block C, ATS BOUQUET, C 401, Block B, Sector 132, Noida, Uttar Pradesh 201304

Get a Consultation

Testing Rust Applications | RemoteState