tree: b5381f486d6d0ab85f63cd52e9e119ee058e0a1b [path history] [tgz]
  1. macro/
  2. src/
  3. tests/
  4. Android.bp
  5. OWNERS
  6. README.md
libraries/rdroidtest/README.md

rdroidtest

This is a custom Rust test harness which allows tests to be ignored at runtime based on arbitrary criteria. The built-in Rust test harness only allows tests to be ignored at compile time, but this is often not enough on Android, where we want to ignore tests based on system properties or other characteristics of the device on which the test is being run, which are not known at build time.

Usage

Unfortunately without the built-in support that rustc provides to the standard test harness, this one is slightly more cumbersome to use. Firstly, add it to the rust_test build rule in your Android.bp by adding the defaults provided:

rust_test {
    name: "mycrate.test",
    defaults: ["rdroidtest.defaults"],
    // ...
}

If you are testing a binary that has a main function, you'll need to remove it from the test build:

#[cfg(not(test))]
fn main() {
    // ...
}

(If you‘re testing a library or anything else which doesn’t have a main function, you don't need to worry about this.)

Each test case should be marked with the rdroidtest attribute, rather than the standard #[test] attribute:

use rdroidtest::rdroidtest;

#[rdroidtest]
fn one_plus_one() {
    assert_eq!(1 + 1, 2);
}

To ignore a test, you can add an ignore_if attribute whose argument is an expression that evaluates to a boolean:

use rdroidtest::{ignore_if, rdroidtest};

#[rdroidtest]
#[ignore_if(!feeling_happy())]
fn clap_hands() {
    assert!(HANDS.clap().is_ok());
}

Somewhere in your main module, you need to use the test_main macro to generate an entry point for the test harness:

rdroidtest::test_main!();

You can then run your tests as usual with atest.

Parameterized Tests

To run the same test multiple times with different parameter values, add an argument to the rdroidtest attribute:

use rdroidtest::rdroidtest;

#[rdroidtest(my_instances())]
fn is_even(param: u32) {
    assert_eq!(param % 2, 0);
}

The initial argument to the rdroidtest attribute is an expression that generates the set of parameters to invoke the test with. This expression should evaluate to a vector of (String, T) values for some type T:

fn my_instances() -> Vec<(String, u32)> {
    vec![
        ("one".to_string(), 1),
        ("two".to_string(), 2),
        ("three".to_string(), 3),
    ]
}

The test method will be invoked with each of the parameter values in turn, passed in as the single argument of type T.

Parameterized tests can also be ignored, using an ignore_if attribute. For a parameterized test, the argument is an expression that emits a boolean when invoked with a single argument, of type &T:

#[rdroidtest(my_instances())]
#[ignore_if(feeling_odd)]
fn is_even_too(param: u32) {
    assert_eq!(param % 2, 0);
}

fn feeling_odd(param: &u32) -> bool {
    *param % 2 == 1
}

Summary Table

NormalConditionally Ignore
Normal#[rdroidtest]#[rdroidtest]
#[ignore_if(<I>)]
Parameterized#[rdroidtest(<G>)]#[rdroidtest(<G>)]
#[ignore_if(<C>)]

Where:

  • <I> is an expression that evaluates to a bool.
  • <G> is an expression that evaluates to a Vec<String, T>.
  • <C> is an callable expression with signature fn(&T) -> bool.