Ignore a test based on environment variable

Viewed 34

There are a few tests that's running locally but not on Github workflows. I've spent quite some time but not able to debug and fix them. For now, I want to ignore them on ci/cd but run them locally. Since, Github provides a handy environment variable CI, which always remains true, can I use that to ignore test?

I don't want to wrap the whole function code under if(env::var("CI").is_ok()). Is there any better way?

2 Answers

One way you could go about doing this is by adding a feature to your Cargo.toml file, like ci or something similar. And then have your GitHub action compile with that feature enabled, and have a conditional compilation attribute on the tests in question.

To do this, you would first add a new feature to your Cargo.toml file:

[features]
ci = []

Then in your Rust code on a test you could write something like this:

#[test]
#[cfg_attr(feature = "ci", ignore)]
fn test_some_code() {
    println!("This is a test");
}

Now locally if you run cargo test you will see the test run, but if you run cargo test --features ci you will see the test shows ignored, like below:

enter image description here

Now you just have to change your GitHub action to compile with this feature. If your action looks something like this:

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Build
      run: cargo build --verbose
    - name: Run tests
      run: cargo test --verbose

Then add --features ci to the end of both the cargo build and cargo test commands.

For more information on conditional compilation, this is in the Rust book: https://doc.rust-lang.org/reference/conditional-compilation.html

For more information on features in Cargo, this is in the Cargo book: https://doc.rust-lang.org/cargo/reference/features.html

To add to pokeyOne's answer, you can include a build script that checks for the CI environment variable and enables a ci feature when it's present. To do this, you would add this build.rs to your project root:

fn main() {
    if std::env::var("CI").is_ok() {
        println!("cargo:rustc-cfg=feature=\"ci\"");
    }
}

Note that build scripts are only run on clean builds, so to test this locally you'll need to run cargo clean between runs (this won't be an issue on CI since you're doing a clean build there).

$ cargo test       # run all tests
$ cargo clean      # make sure build.rs is re-run...
$ CI=1 cargo test  # skip CI tests

Features are a special type of --cfg flag, used for conditional compilation. Instead of using a feature, you could instead use a single identifier --cfg flag, like so:

// build.rs
fn main() {
    if std::env::var("CI").is_ok() {
        println!("cargo:rustc-cfg=ci");
    }
}

// src/main.rs
#[cfg(test)]
mod tests {
  // ..(snip)..

  #[test]
  #[cfg(not(ci))]
  fn breaks_on_ci() { ... }
}

This build.rs is equivalent to running

$ RUSTFLAGS="--cfg ci" cargo test

You can read more about build scripts, --cfg flags, and conditional compilation in the Rust book here.

Related