yegor256
yegor256

Reputation: 105053

How to pass parameters generated by a method to a Rust unit test?

I'm trying to write a parametrized unit test in Rust, which will take parameters from a method. I know how to use rstest when parameters are hardcoded:

use rstest::rstest;

#[rstest]
#[case(42)]
#[case(256)]
fn my_test(#[case] x: i32) {
  assert!(x > 0)
}

However, I want something like this:

#[cases_from(my_provider)]
fn my_test(#[case] x: i32) {
  assert!(x > 0)
}

fn my_provider() -> Vec<i32> {
  [42, 256].to_vec()
}

Is is possible with rstest? If not, which library enables this?

Upvotes: 1

Views: 993

Answers (1)

kmdreko
kmdreko

Reputation: 59952

It does not appear to be possible with rstest, though a similar feature has been asked for: Issue #39: Dynamic set of tests. There is difficulty because the library is designed around generating individual test functions that are then ran and displayed separately by the standard cargo test harness. And to do that, the procedural macros at play need all the pieces. It is not implemented by a simple for-loop over the test cases.

If you simply desire a mechanism to use the same set of test cases for multiple tests, the developer has created the rstest-reuse crate which would be used like this:

#[template]
#[rstest]
#[case(2, 2)]
#[case(4/2, 2)]
fn two_simple_cases(#[case] a: u32, #[case] b: u32) {}

#[apply(two_simple_cases)]
fn it_works(a: u32, b: u32) {
    assert!(a == b);
}

#[apply(two_simple_cases)]
fn it_fail(a: u32, b: u32) {
    assert!(a != b);
}

If you're fine with a single test that loops over inputs (and therefore loses some visibility into which test failed and functionality to continue with other cases), then you can simply write that yourself:

#[test]
fn my_test() {
    fn my_test_inner(x: i32) {
        assert!(x > 0)
    }

    for x in my_provider() {
        my_test_inner(x);
    }
}

fn my_provider() -> Vec<i32> {
    [42, 256].to_vec()
}

Upvotes: 1

Related Questions