Я пытаюсь составить общее решение для предоставления приспособлений для модульного тестирования кода Rust. Я придумал макрос, который позволяет пользователю определять методы setup и teardown . Вот мое решение:
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: identity $ fixt: ident $ ftype: ty $ expr: expr) = & gt; (
Как видите, в определении макроса я заменил ссылки на FooTestFixture на $ ftype.
Возможно ли то, чего я пытаюсь достичь? Это похоже на то, как если бы я хотел, чтобы макрос был универсальным, позволяя вам передавать тип, который будет использоваться внутри определения макроса.
2 ответа
Что ж, я понял, что в конце концов мне не нужен 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");
});
За ty
не может сразу идти expr
. Это должно быть , за которым следует определенный набор токенов а>:
=>
,
=
|
;
:
>
[
{
as
where
Аналогичное ограничение существует после expr
, stmt
, path
и pat
. Это было введено в RFC 550 для будущего -устойчивое возможное изменение синтаксиса Rust.
Чтобы исправить это, вам нужно изменить шаблон макроса, например
macro_rules! unit_test {
($name:ident $fixt:ident<$ftype:ty> $expr:expr) => (
// ^ ^ followed by '>' is OK
unit_test! (test_name fixture_name<FooTestFixture> f {
// ^ ^
Похожие вопросы
Новые вопросы
unit-testing
Модульное тестирование - это метод, с помощью которого отдельные блоки исходного кода тестируются, чтобы определить, пригодны ли они для использования.