Есть ли простой способ условно включить или игнорировать целые тестовые наборы в Rust? - PullRequest
0 голосов
/ 28 мая 2018

Я работаю над библиотекой Rust, которая предоставляет доступ к некоторым аппаратным устройствам.Существует два типа устройств, 1 и 2, и функциональность для типа 2 является расширенным набором функциональных возможностей для типа 1.

Я хочу предоставить разные тестовые наборы для разных обстоятельств:

  • тесты без подключенного устройства (базовые проверки работоспособности, например, для серверов CI)
  • тесты для общей функциональности (требуется устройство типа 1 или 2)
  • тесты для эксклюзивного типа 2функциональность (требуется устройство типа 2)

Я использую функции для представления этого поведения: функция по умолчанию test-no-device и дополнительные функции test-type-one и test-type-two.Затем я использую атрибут cfg_attr, чтобы игнорировать тесты, основанные на выбранных функциях:

#[test]
#[cfg_attr(not(feature = "test-type-two"), ignore)]
fn test_exclusive() {
    // ...
}

#[test]
#[cfg_attr(not(any(feature = "test-type-two", feature = "test-type-one")), ignore)]
fn test_shared() {
    // ...
}

Это довольно громоздко, поскольку мне приходится дублировать это условие для каждого теста, а условия трудно читать и поддерживать.

Есть ли более простой способ управления наборами тестов?

Я пытался установить атрибут ignore при объявлении модуля, но, очевидно, его можно установить только для каждого testфункция.Я думаю, что я мог бы отключить компиляцию исключенных тестов, используя cfg на модуле, но так как тесты должны всегда компилироваться, я бы хотел избежать этого.

1 Ответ

0 голосов
/ 28 мая 2018

Есть ли простой способ условно включить или игнорировать все наборы тестов в Rust?

Самый простой - это даже не компилировать тесты:

#[cfg(test)]
mod test {
    #[test]
    fn no_device_needed() {}

    #[cfg(feature = "test1")]
    mod test1 {
        fn device_one_needed() {}
    }

    #[cfg(feature = "test2")]
    mod test2 {
        fn device_two_needed() {}
    }
}

Я должен дублировать это условие для каждого теста, и условия трудно читать и поддерживать.

  1. Можете ли вы представить желаемую функциональность в чистом Rust? да
  2. Является ли существующий синтаксис слишком многословным? да

Это кандидат на макрос.

macro_rules! device_test {
    (no-device, $name:ident, {$($body:tt)+}) => (
        #[test]
        fn $name() {
            $($body)+
        }
    );
    (device1, $name:ident, {$($body:tt)+}) => (
        #[test]
        #[cfg_attr(not(feature = "test-type-one"), ignore)]
        fn $name() {
            $($body)+
        }
    );
    (device2, $name:ident, {$($body:tt)+}) => (
        #[test]
        #[cfg_attr(not(feature = "test-type-two"), ignore)]
        fn $name() {
            $($body)+
        }
    );
}

device_test!(no-device, one, {
    assert_eq!(2, 1+1)
});

device_test!(device1, two, {
    assert_eq!(3, 1+1)
});

функциональность для типа 2 является расширенной функциональностью для типа 1

Отразите это в своих определениях функций, чтобы упростить код:

[features]
test1 = []
test2 = ["test1"]

Если вы сделаете это, вам не нужно иметь any или all в вашематрибуты конфигурации.

функция по умолчанию test-no-device

Это не кажется полезным;вместо этого используйте обычные тесты, защищенные обычной конфигурацией тестирования:

#[cfg(test)]
mod test {
    #[test]
    fn no_device_needed() {}
}

Если вы выполните это, вы можете удалить этот случай из макроса.


Я думаю, что если вы будете следовать обоим предложениям, вам даже не нужен макрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...