Как убедиться в отсутствии багов?

«Как убедиться в отсутствии багов?» — вопрос из категории Тестирование, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Полная гарантия невозможна, но комбинация практик значительно снижает количество дефектов. В моих C++ проектах я применяю многоуровневый подход:

1. Предотвращение на этапе написания:

  • Стиль и стандарты: Строгое следование clang-format и правилам из clang-tidy.
  • Идиомы C++: Активное использование RAII (std::unique_ptr, std::lock_guard), семантики перемещения, умных указателей для автоматического управления ресурсами.

2. Статический анализ:

  • Использую clang-tidy и cppcheck в CI/CD пайплайне.
  • Включаю все предупреждения компилятора (-Wall -Wextra -Wpedantic для GCC/Clang, /W4 для MSVC) и трактую их как ошибки (-Werror).

3. Динамический анализ и тестирование:

  • Юнит-тесты: Пишу тесты с помощью Google Test для всех нетривиальных функций и классов.
    // Пример простого теста с Google Test
    TEST(MathTest, SumPositive) {
    EXPECT_EQ(sum(2, 2), 4);
    EXPECT_EQ(sum(0, 5), 5);
    }
  • Санитайзеры: Запускаю тесты под AddressSanitizer (ASan) и UndefinedBehaviorSanitizer (UBSan) для поимки ошибок памяти и неопределённого поведения.
  • Валгринд: Для глубокой проверки утечек памяти (особенно в legacy-коде) использую Valgrind Memcheck.

4. Процессные меры:

  • Code Review: Обязательный ревью всех изменений коллегами.
  • Интеграционное тестирование: Сквозные тесты ключевых сценариев работы приложения.
  • Фаззинг: Для обработки внешних данных (парсеры, сетевые протоколы) иногда применяю фаззинг-тесты с помощью libFuzzer.