Основы тестирования программного обеспечения на Rust

Beginner

This tutorial is from open-source community. Access the source code

Введение

В этом лабораторном задании мы исследуем важность тестирования при разработке программного обеспечения на Rust и узнаем, как писать различные виды тестов, такие как модульные тесты и интеграционные тесты. Мы также узнаем, как организовать тесты в проектах на Rust и запускать их с помощью команды cargo test. Кроме того, мы обсудим возможные проблемы, которые могут возникнуть при параллельном запуске тестов, и приведем пример, иллюстрирующий это.

Примечание: Если в лабораторном задании не указано имя файла, вы можете использовать любое имя файла, которое хотите. Например, вы можете использовать main.rs, скомпилировать и запустить его с помощью rustc main.rs &&./main.

Тестирование

Как мы знаем, тестирование является неотъемлемой частью любого программного обеспечения! Rust имеет первоклассную поддержку для модульных и интеграционных тестов (см. этот раздел в TRPL).

Из разделов о тестировании, ссыланных выше, мы узнаем, как писать модульные и интеграционные тесты. Организационно мы можем размещать модульные тесты в модулях, которые они тестируют, а интеграционные тесты в собственной директории tests/:

foo
├── Cargo.toml
├── src
│   └── main.rs
│   └── lib.rs
└── tests
    ├── my_test.rs
    └── my_other_test.rs

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

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

cargo естественно предоставляет простой способ запустить все ваши тесты!

$ cargo test

Вы должны увидеть вывод в таком виде:

[object Object]

Вы также можете запустить тесты, чье имя соответствует шаблону:

$ cargo test test_foo
[object Object]

Одна важная вещь: Cargo может запускать несколько тестов одновременно, поэтому убедитесь, что они не конфликтуют друг с другом.

Одним примером, когда параллелизм вызывает проблемы, является ситуация, когда два теста выводят данные в файл, как ниже:

#[cfg(test)]
mod tests {
    // Импортируем необходимые модули
    use std::fs::OpenOptions;
    use std::io::Write;

    // Этот тест записывает данные в файл
    #[test]
    fn test_file() {
        // Открывает файл ferris.txt или создает его, если он не существует.
        let mut file = OpenOptions::new()
         .append(true)
         .create(true)
         .open("ferris.txt")
         .expect("Failed to open ferris.txt");

        // Печатает "Ferris" 5 раз.
        for _ in 0..5 {
            file.write_all("Ferris\n".as_bytes())
             .expect("Could not write to ferris.txt");
        }
    }

    // Этот тест пытается записать данные в тот же файл
    #[test]
    fn test_file_also() {
        // Открывает файл ferris.txt или создает его, если он не существует.
        let mut file = OpenOptions::new()
         .append(true)
         .create(true)
         .open("ferris.txt")
         .expect("Failed to open ferris.txt");

        // Печатает "Corro" 5 раз.
        for _ in 0..5 {
            file.write_all("Corro\n".as_bytes())
             .expect("Could not write to ferris.txt");
        }
    }
}

Хотя ожидаемый результат следующий:

$ cat ferris.txt
Ferris
Ferris
Ferris
Ferris
Ferris
Corro
Corro
Corro
Corro
Corro

В самом файле ferris.txt на самом деле находится следующее:

$ cargo test test_foo
Corro
Ferris
Corro
Ferris
Corro
Ferris
Corro
Ferris
Corro
Ferris

Резюме

Поздравляем! Вы завершили лабораторную работу по Тестированию. Вы можете практиковаться в других лабораторных работах в LabEx, чтобы улучшить свои навыки.