我试图组成一个通用的解决方案,为单元测试锈蚀代码提供固定装置。我已经想出了一个宏,它允许用户定义安装和解压方法。到目前为止,我的解决方案如下:
struct FooTestFixture {
pub name : String
}
impl FooTestFixture {
fn setup() -> FooTestFixture {
FooTestFixture { name: String::from("Initialised") }
}
}
fn teardown(fixture : &mut FooTestFixture) {
fixture.name = "".to_string();
}
macro_rules! unit_test {
($name:ident $fixt:ident $expr:expr) => (
#[test]
fn $name() {
let mut $fixt : FooTestFixture = FooTestFixture::setup();
$expr;
teardown(&mut $fixt);
}
)
}
unit_test! (heap_foo_fixture_should_be_initialised_using_macro f {
assert_eq!(f.name, "Initialised");
});这个很管用。唯一的问题是,宏unit_test不是泛型的,并且绑定到夹具名称FooTestFixture。这意味着每个测试模块都需要为每个测试夹具重新定义这个宏,这并不理想。我想要做的是也引入一个类型变量,并在宏展开中使用该类型。深入研究宏,我发现有一个'ty‘项,它代表一个类型,我认为我可以这样做……
macro_rules! unit_test {
($name:ident $fixt:ident $ftype:ty $expr:expr) => (
#[test]
fn $name() {
let mut $fixt : $ftype = $ftype::setup();
$expr;
teardown(&mut $fixt);
}
)
}
unit_test! (heap_foo_fixture_should_be_initialised_using_macro FooTestFixture f {
assert_eq!(f.name, "Initialised");
});但是,这不起作用,并导致以下错误:
src\tests\heap_fixture_with_new.rs:48:40: 48:50错误:
$ftype:ty后面跟着$expr:expr,不允许ty片段src\tests\heap_fixture_with_new.rs:48 ($name:ident $fixt:ident $ftype:ty $expr:expr) => (
如您所见,在宏定义中,我已将对FooTestFixture的引用替换为$ftype。
我想达到的目标是可能的吗?这几乎就像我希望这个宏是泛型的,允许您传递一个类型,在宏定义中使用。
发布于 2016-05-05 19:51:36
我终于意识到我不需要ty了。我只需将类型指定为ident参数,这样就可以执行以下操作:
macro_rules! unit_test {
($name:ident $fixt:ident $ftype:ident $expr:expr) => (
#[test]
fn $name() {
let mut $fixt = $ftype::setup();
$expr;
teardown(&mut $fixt);
}
)
}
unit_test! (foo_fixture_should_be_initialised_using_generic_macro f FooTestFixture {
assert_eq!(f.name, "Initialised");
});发布于 2016-05-05 19:51:44
ty不能直接跟在expr后面。一定是后面跟着一组特定的令牌
=>,=|;:>[{aswhere在expr、stmt、path和pat之后也存在类似的限制。这是在RFC 550引入到未来防锈语法的潜在变化中的。
要修复它,您需要改变宏的模式。
macro_rules! unit_test {
($name:ident $fixt:ident<$ftype:ty> $expr:expr) => (
// ^ ^ followed by '>' is OK
unit_test! (test_name fixture_name<FooTestFixture> f {
// ^ ^https://stackoverflow.com/questions/37058836
复制相似问题