1.11 Испытание
Сделать и проверить - не одно и то же. Мастер, только что закончивший изделие, знает одно: оно выглядит готовым. Правда ли оно готово - другой вопрос, и ответ на него не видно глазами. Задача умеет создавать себя, завершаться и отвечать на вопрос о своём состоянии. Вера удобна: не требует инструментов и работает мгновенно. Цена удобства обнаруживается именно тогда, когда всё начинает идти не так.
Что нужно
make ci проверяет форму: форматирование без нареканий, clippy без предупреждений. О
поведении он не спрашивает. Код, который выглядит правильно, может вести себя неправильно -
застава этого не заметит.
Нужен способ задавать вопросы о поведении и требовать ответа при каждом запуске.
Сборка
Тесты живут в специальном блоке в конце файла:
#[cfg(test)]
mod tests {
use super::*;
}
#[cfg(test)] - атрибут конфигурации: этот блок компилируется только при cargo test. В
обычную сборку он не попадает. use super::* вводит типы из родительского файла в область
видимости тестов - без него Task и Status внутри блока неизвестны.
Тест - обычная функция с атрибутом #[test]. Имя описывает проверяемое поведение, а не
метод:
#[test]
fn new_task_starts_as_todo() {
let task = Task::new(1, "Buy coffee");
assert!(!task.is_done());
}
assert! проверяет условие: если оно ложно - тест падает. Добавим второй тест:
#[test]
fn complete_marks_task_done() {
let mut task = Task::new(1, "Buy coffee");
task.complete();
assert!(task.is_done());
}
Когда нужно сравнить два значения, assert_eq! покажет оба при падении:
#[test]
fn task_id_is_preserved() {
let task = Task::new(42, "Buy coffee");
assert_eq!(task.id, 42);
}
assert_eq!(left, right) - если left != right, тест падает и печатает оба значения.
assert! этого не делает: он знает только “ложь”.
Итог
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_task_starts_as_todo() {
let task = Task::new(1, "Buy coffee");
assert!(!task.is_done());
}
#[test]
fn complete_marks_task_done() {
let mut task = Task::new(1, "Buy coffee");
task.complete();
assert!(task.is_done());
}
#[test]
fn task_id_is_preserved() {
let task = Task::new(42, "Buy coffee");
assert_eq!(task.id, 42);
}
}
running 3 tests
test tests::complete_marks_task_done ... ok
test tests::new_task_starts_as_todo ... ok
test tests::task_id_is_preserved ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
make ci проходит. Застава теперь спрашивает не только о форме.
Полный код
tqдля этой главы -1-a-task/11-the-first-proof/.
Lore: что не тестируется
Тесты проверяют поведение через возвращаемые значения и состояние. list возвращает () и
только печатает - чтобы проверить вывод, нужно перехватывать stdout. Это возможно, но
инструменты для этого появятся позже.