For context: I'm new to rust and, most recently, come from Python and C. I'm looking for a way to achieve some of the matrix unit testing I am familiar with from Python's Pytest. In particular I'm interested in replicating Pytest's parameterized fixtures which very easily let you create test cases for a cartesian product of input values.
The project I'm working on has some stock data-sets which can be expressed as static arrays, each of 5-20 values. From experience in Python, there's real value in testing every permiatation where a function may be interested in 2-3 of these. Yes!, this results in approx 2,000 - 4,000 test cases in total.
I'm currently looking at the test-case crate which get's me a long way forward when I copy-paste the static arrays into the macro #[test_matrix()] arguments.
@zirconium-n yes, that's how you declare a static array...
The question is how to use that with a macro similar to test_matrix?
Perhapse I should have mentioned that attempting to pass an argument like TEST_DATA into the macro has resulted in type errors because it is expecting the argument type to match the test-function type...
... That's not what I'm looking for the test function type needs to be the type of just one element, not the type of the array itself. That is, the test function type needs to be i8 not [i8; 2] and not &[i8].
With python test_matrix, does it automatically pass each row as parameters to your test function? I don't know a way to do that automatically (declaratively) in Rust, so I would just write the for loop for each test. You can refer to the same static/const test data from multiple tests, if you declare that test data in the test module.
Perhaps it is possible to write a Rust macro that outputs the for loop, but I will have to defer on that to those who know more about Rust macros.
@jumpnbrownweasel I've not interrigated the code, but for rust macro test_matrix AFAIK it's a macro that is writing out #[test] functions which individually pass arguments into the test function I've written. So the above snipit results in cargo test reporting on 4 tests.
Pytest in python is a runtime framework, so it's a lot simper to do the same thing there.
Macros work on tokens, so in order to have m * n test functions generated, you need m tokens in one list and n tokens in another. You could do that by making your own macro that generates the test_matrix attributes. This would need to either be another procedural attribute macro, or a declarative macro that wraps the function. Probably something like this (using tokio::test since that's in the playground): Rust Playground
It looks like the test_matrix is able to expand the [ ... ] of the second but not the first. Somehow for the first it seems to see just one token and does not expand the square brackets.
Macro expansion works from the outside in. It's the opposite of function calls. So the test_matrix thing is being expanded and passed foo!() as a string, not the expansion of foo!.
But setting aside all the details about macros for a second... consider writing some normal code for this, something like
#[test]
fn test_bar() {
for test_case in TEST_CASES {
bar(test_case);
}
}
Later, once you've got a dozen of those, it'll be much more obvious how you should use macros to eliminate boilerplate.