Как стать автором
Обновить

Кратко про юнит-тесты в Rust

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров2.7K
Всего голосов 13: ↑12 и ↓1+11
Комментарии9

Комментарии 9

Параметризованные тесты

А так, чтобы параметры кодом генерировать вместо констант, сейчас возможно? Пару лет назад не нашёл такого способа, плюнул, сделал циклами внутри обычного #[test].

Если что-то а ля фаззинг то kani и proptest по идее ваш клиент.

Не фаззинг, а просто генерация тест кейсов кодом. (Пример как это в NUnit)
Иногда в константы кейсы трудно запихать из-за сложной логики создания входных данных

Какой-то такой код похож на то что делает NUnit?

use proptest::prelude::*;

fn add(a: i32, b: i32) -> i32 {
    a + b
}

proptest! {
    #[test]
    fn test_add(a in 0..1000i32, b in 0..1000i32) {
        let sum = add(a, b);
        assert!(sum >= a);
        assert!(sum >= b);
    }
}

fn main() { test_add(); }

Вместо копипасты с генераторами тут будут рэнжи с данными a in 0..1000i32 или v in any::<u32>().prop_map(|v| v.to_string()) как вот тут. Собственно вторым способом наверняка можно также тесткейсы из массива и как кортеж обрабатывать, аналогично примеру с NUnit, где кейсы были массивами объектов/классов, но это надо маны читать, сам не пользовался.

Kani тоже умеет в генерацию, но он все же больше про фаззинг, нежели про протесты.

Похож, но всё же не то. Тут именно ренжи и всякие их any::<u32>() являются источником данных и явного способа впихнуть туда полностью кастомно генерируемый массив своих данных не видно. Накостылять наверняка можно, но выглядеть полагаю уже будет не сильно читаемо.

Так можно использовать обычные массивы вместо any. Будет что-то вроде

proptest! {
    #[test]
    fn test_add((a,b,c) in 
    [ (3,4,5),
      (6,7,8),
      (9,10,11),].into_iter()) 
    {
      let sum = add(a,b);
      let sum2 = add(b,c);
      let sum3 = add(sum, sum2);
      assert!(sum3 == a + b + c)
    }

Написал наугад, но в принципе можно по красоте сделать с итераторами и композерами.

Не, напрямую так не получится :(

the trait `Strategy` is not implemented for `{integer}`, which is required by `({integer}, {integer}): Strategy`

После in должно идти что-то имплементирующее Strategy trait, который всякие возможности перебора и упрощения комбинаций значений должен предоставлять. Поэтому нужно именно что костылять с dummy имплементаций трейта которая бы возвращала определенный список значений, причём так, чтобы proptest не резал некоторые значения как избыточные при симплификации.

В Rust нет ограничений на тестирование приватных функций

Это ж пока пишешь тесты прям в тексте самого файла, который тестировать будешь? А если эти же тесты вынести за пределы файла, в папку tests? Там уже вроде ограничения уже есть. Это конечно возможно только для модулей, для бинарных пакетов такое сделать нельзя, там только писать тесты внутри самих исходников. Или я что-то путаю?

В статье формулировка не полная.

Доступ к приватным сущностям в расте есть из любого кода, который расположен в модуле не выше того, где определена приватная сущность.

При этом каким образом модули раскиданы по папкам и файлам - не имеет значение. Значение имеет только иерархия модулей.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий