Past, present, and future for Rust testing

It’s worth discussing trait level design-by-contract or trait integration test consisting of two features:

  • permit #[test] on inherent and trait methods that do not require arguments and
  • provide a #[required_of_client] attribute for trait impls.

Right now, you could add macros that generate test code to test trait impls, but they must be called manually. If you wanted to enforce it, then you’d need something more:

pub trait Foo {
    fn foo(&self);
}

#[cfg(test)]
pub trait FooTester : Foo {
    #[cfg(test)]
    fn test_new() -> Box<Self>;
}

#[cfg(test)]
mod test {

#[require_of_client]
impl<F: Foo> FooTester for F;

impl<F: Foo> F {
    #[test]
    fn do_foo_test() {
        let me = test_new();
        ...
    }
}

} // mod test

In this, the #[require_of_client] demands the impl exist but does not provide test_new itself. Also F::do_foo_test() is an inherent method for any Foo that only exists here and becomes a test.

You might need the #[test] to appear inside the FooTester trait sometimes trait too. I used Box<Self> here so that test_new need not be Sized, but maybe some use cases still need it, like tests in no_std.