Юнит-тестирование

Введение в юнит-тесты

Последнее обновление: 20.05.2024

Юнит-тесты представляют важный компонент разработки, который помогает обеспечить корректность выполнения кода. В языке Rust имеется встроенная поддержка юнит-тестов. Рассмотрим основные моменты юнит-тестирования на Rust.

Прежде всего нам надо создать новый проект cargo, поскольку запуск тестов производится с помощью инфраструктуры пакетного менеджера cargo. Так, перейдем в консоли к папке, где мы хотим создать проект, и выполним следующую команду

cargo new testapp

Наш проект будет называться testapp

Написание тестов

Тест по сути представляет собой функцию, к которой применяется атрибут #[test]. Этот атрибут сообщает компилятору Rust, что функция представляет тест, и ее следует включать в тестовые прогоны.

Где располагается тест? В данном случае в реальности нет каких-то четких требований. Например, мы можем помещать функциии/функционал и их тестыв один файл, можно разделять их. Можно выделять тесты в отделньые модули. Далее посмотрим на некоторые сценарии. Но сначала рассмотрим, что вообще представляет простейший тест. И для простоты пока весь определим в файле main.rs, который располагается в папке src:

fn main() {
    println!("Hello, world!");
}

fn add(a: i32, b: i32) -> i32 { // функция для тестирования

    a + b
}

// функция-тест
#[test]
fn test_add() { 

    // Arrange
    let input_1 = 2;
    let input_2 = 8;
    // Act
    let result = add(input_1, input_2);
    // Assert
    assert_eq!(result, 10, "The addition result is incorrect.");
}

Итак, здесь у нас есть функция add(), которая складывает два числа и возвращает их сумму. И к этой функции определен тест - функция test_add(). Обратите внимание, что эта функция предваряется атрибутом #[test]. Внутри функции определяем два значения для параметров функции add и вызываем ее, сохраняя ее результат в переменную result.

Далее нам надо верифицировать результат. Для этого стандартная библиотека языка Rust предоставляет ряд макросов, которые в дальнейшем мы вкратце рассмотрим. В частности, макрос assert_eq!() позволяет проверить на равенство два значения. Его первые два параметра представляют значения, которые проверяются на равенство, а третий параметр представляет сообщение, которое выводится при неравенстве. Так, мы складываем числа 2 и 8 и ожидаем, что результат будет равен 10. Если результат будет равен 10, то тест будет пройден. Если же результат не будет равен 10, то тест не будет пройден, а на консоль будет выводиться сообщение "The addition result is incorrect.".

Данный тест соответствует шаблону "Arrange, Act, Assert" (AAA) (иными словами "Настройка функции, Вызов функции, Подтверждение результата), где этап "Arrange" включает в себя настройку необходимых входных данных и условий, этап "Act" выполняет тестируемую операцию, а этап "Assert" проверяет, что мы получили тот результат, который ожидали.

Теперь перейдем в консоли в папку проекта и запустим тест. Для запуска юнит-тестов в Rust в общем случае применяется команда cargo test:

eugene@Eugene:~/Documents/rust/testapp$ cargo test
   Compiling testapp v0.1.0 (/home/eugene/Documents/rust/testapp)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.11s
     Running unittests src/main.rs (target/debug/deps/testapp-484a4e49d8e25663)

running 1 test
test test_add ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

eugene@Eugene:~/Documents/rust/testapp$ 

Результаты тестов

После выполнения тестов нам отобразится отчет c результатами. В этом отчете мы сможем увидеть, какие тесты были успешно пройдены, а какие нет. Кроме того, мы можем увидеть некоторую дополнительную информацию, в частности, время выполнения.

Так, средняя часть сводки говорит нам, сколько тестов и какие именно тесты запускаются:

running 1 test
test test_add ... ok

Так, мы видим, что был запущен 1 тест, который называется "test_add" - название нашей функции-теста.

И в последней части сводки мы види результат тестирования:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Если тест успешно пройден, как в нашем случае, то он получает статус "passed". И в нашем случае мы видим в своде "1 passed".

Если тест НЕ пройден, то он получает статус "failed". В нашем случае таких тестов нет, на что указывает запись "0 failed".

Возможна ситуация, когда у нас есть тесты, но мы их не хотим запускать - такие функции тестов предваряются атрибутом #[ignore] и при тестировании получают статус "ignored". В нашем случае таких также нет, на что указывает запись "0 ignored"

Но теперь изменим код следующим образом:

fn main() {
    println!("Hello, world!");
}

fn add(a: i32, b: i32) -> i32 { // функция для тестирования

    a - b   // некорректное поведение
}

// функция-тест
#[test]
fn test_add() { 

    let input_1 = 2;
    let input_2 = 8;
    let result = add(input_1, input_2);
    assert_eq!(result, 10, "The addition result is incorrect.");
}

Теперь наша функция add вместо сложения выполняет вычитание. Однако в функции-тесте test_add() мы по-прежнему ожидаем, что функция add() будет выполнять сложение. Также запустим тест:

eugene@Eugene:~/Documents/rust/testapp$ cargo test
   Compiling testapp v0.1.0 (/home/eugene/Documents/rust/testapp)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.08s
     Running unittests src/main.rs (target/debug/deps/testapp-484a4e49d8e25663)

running 1 test
test test_add ... FAILED

failures:

---- test_add stdout ----
thread 'test_add' panicked at src/main.rs:20:5:
assertion `left == right` failed: The addition result is incorrect.
  left: -6
 right: 10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    test_add

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--bin testapp`
eugene@Eugene:~/Documents/rust/testapp$ 

И теперь мы видим совсем другой результат: тест не пройден. То есть наша функция add работает некорректно. Мы видим в сводке, более детальную информацию и наше сообщение об ошибке:

assertion `left == right` failed: The addition result is incorrect.
  left: -6
 right: 10

То есть условие неверно, ожидали получить 10, а получили -6. Соответственно нам надо вернуться к коду, исправить его, снова выполнить тест и повторять эти действия, пока тест не будет пройден.

Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850