harness = false
The test crate is unstable, and likely to be for a while. It’d be good to experiment a bit on crates.io. To support this, Cargo allows specifying in Cargo.toml:
[[test]]
name = "foo"
harness = false
(Note: when you do this Cargo stops enumerating tests/*.rs implicitly and you need an explicit [[test]] section for every test file.)
This causes cargo test to not rustc --test when compiling that test file and instead compile it as an executable with a main() function. Then it’s up to you to test stuff and exit a non-zero status code on failure.
[dependencies] rustc-test = "0.1"
Testing with nothing but main() and assert!() is not very nice.
I’ve extracted the test crate, forked it so that it runs on stable Rust*, and published it at https://crates.io/crates/rustc-test/. Please note that I’m not interested in maintaining or developing a test harness, this is mostly to demonstrate what’s possible today on the stable channel. I’d be happy to give ownership on crates.io if someone is interested.
(* With some caveats: capturing test output and the asm! implementation of black_box are behind Cargo features disabled by default since they require unstable features.)
With this, you can create a list of tests with the appropriate structs, call test::test_main(), and it works just like rustc --test. This is great for “data driven” tests that are generated dynamically with the same code and different input an expected output (which is not possible to do with rustc --test today). See html5ever’s tests/tree_builder.rs for example. But if you have many tests functions, this is not as nice as slapping #[test] on them.
#[test]
Which leads to the point of this thread. Using an external test harness is possible today, but using #[test] with it rather then having to enumerate test functions yourself would be nice.
Most of what rustc --test does is implemented in src/libsyntax/test.rs. Namely, it generates a module that looks like:
mod __test {
extern crate test (name = "test", vers = "...");
fn main() {
test::test_main_static(&::os::args()[], tests)
}
static tests : &'static [test::TestDescAndFn] = &[
... the list of tests in the crate ...
];
}
So I’d like to (first introduce as unstable and then) stabilize building blocks for external test harnesses:
- A simplified version of
TestDescAndFn, with just enough to describe whatrustc --testgenerates. (So probably without dynamic tests.) - Some way to override which crate/function is used instead of
test::test_main_static. Maybe#[test_harness] extern crate fancy_test;? (If benchmark are supported in this mechanism,TestDescAndFnwould probably have to be generic overBencher.)
Does this sound like it’s worth pursuing?
