СИСТЕМНОЕ И ПРИКЛАДНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ Лекция 13. Виды тестирования. Подходы к созданию тестов. План тестирования. Инструменты тестирования. Цель и виды тестирования Зачем тестировать? • Цель – контроль качества ПО • • • • • • Надёжность Сопровождаемость Практичность Эффективность Мобильность Функциональность 3 Что тестируют • Функциональность • Интерфейс пользователя • внешний вид • локализация • Удобство использования • Нагрузки • производительность • стабильность • Безопасность • Совместимость 4 Виды тестирования 1. Функциональное 2. Нефункциональное 3. Связанное с изменениями 5 1. Функциональное тестирование • Тестирование функциональности • тестовые случаи (провека корректности) • тестовые сценарии (проверка соответствия бизнес-требованиям) • Тестирование безопасности • базовые принципы: конфиденциальность, целостность, доступность • Тестирование взаимодействия • совместимость с внешними системами и компонентами 6 Функциональное тестирование: уровни • Модульное (компонентное) • Интеграционное • интерфейсы, взаимодействие компонент • Системное • Альфа-тестирование - регрессионное - новая функциональность - приёмочное • Бета-тестирование 7 2. Нефункциональное тестирование • • • • Тестирование производительности Тестирование инсталляции Тестирование удобства использования Тестирование на отказ/восстановление после сбоев • Конфигурационное тестирование • проверка работы на разных системных конфигурациях (в т.ч. профилирование и миграция на другую платформу) 8 Тестирование производительности • Нагрузочное тестирование • определение масштабируемости под нагрузкой - время выполнения операций количество одновременных сеансов пользователей поиск границы приемлемой производительности изучение производительности на предельных нагрузках • Стрессовое тестирование • проверка работоспособности в целом на пиковых нагрузках • Объёмное тестирование • зависимость производительности от роста объёмов данных • Тестирование стабильности/надёжности • длительное тестирование под «нормальной» нагрузкой - проверка на отсутствие утечек ресурсов, длительность работы без перезапуска под нагрузкой 9 Тестирование удобства использования (usability) • Эффективность • время/усилия пользователя для выполнения задачи • Правильность • количество ошибок пользователя • Активация в памяти • насколько легко пользоваться программой повторно после перерыва • Эмоциональная реакция • состояние пользователя после завершения задачи 10 3. Тестирование, связанное с изменениями • Дымовое тестирование • базовые проверки работоспособности • Регрессионное тестирование • проверка, что изменения не «испортили» существующую функциональность • Тестирование сборки • вариант дымового тестирование – базовая проверка качества новой версии • Проверка исправности (Sanity testing) • проверка работоспособности определённой функции (после изменений) 11 Виды тестов Виды тестов По знанию системы: • Внутренняя структура: • Чёрный ящик • Белый ящик • Отношение к документации: • Формальное, по документации • «Интуитивное» 13 Виды тестов По характеру • Позитивные • Негативные По способу выполнения • Ручные • Автоматические 14 Про тщательность тестирования • Пример: Вычисление квадратного корня • f(x) = sqrt(x) • Возможные реализации: • Метод Ньютона - поиск неподвижной точки функции f(y) = x / y • начальное предположение y_0 (в идеале, близкое к sqrt(x)) • итеративное приближение: y_(n+1) = ½(y_n + x / y_n) - Что тестировать: • сходимость метода на малых и больших величинах • некорректный ввод (отрицательные) • “Fast inverse square root” f(x) = 1/sqrt(x) - Алгоритм из графического движка игры quake3 • Хак с получением довольно точного приближения к • 1-2 итерации метода Ньютона - Что тестировать: • корректность такого хака в принципе 15 Fast inverse square root float Q_rsqrt( float number ) { const float threehalfs = 1.5F; float x2 = number * 0.5F; float y = number; // evil floating point bit level hacking: long i = * ( long * ) &y; i = 0x5f3759df - ( i >> 1 ); // WTF? y = * ( float * ) &i; // 1st iteration: y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed y = y * ( threehalfs - ( x2 * y * y ) ); return y; } 16 Процесс тестирования Процесс тестирования • Планирование • результат – план тестирования - условия, стратегия, объём работ • Проектирование тестов • формирование набора тестов (Test Suite) - в соответствии с требованиями • Тестирование • дымовое->регрессионное->прочее • Анализ результатов 18 Пплан тестирования: примерное содержание 1. 2. 3. 4. 5. 6. 7. Вводное описание тестируемого приложения или системы Что тестировать: • требования, нуждающиеся в проверке Как тестировать • применяемые виды тестирования (зачем и где) • инструменты • артефакты (отчёты, логи, ...) Когда тестировать: • место процесса тестирования в проектном плане Критерии готовности к тестированию • готовность функций, документации, тестовых стендов Критерии окончания тестирования • критерии качества, достаточные для завершения испытаний Ответственные 19 План тестирования: стандарты • IEEE 829-2008 – “Standard for Software and System Test Documentation” • RUP: Test Plan 20 Проектирование тестов • Спецификация дизайна • что тестировать: - тестируемая функция - ссылки на документацию - используемый подход тестирования • методы, цели, сценарии • Описание тестовых случаев (test cases) • как тестировать: - название тестового случая, проверяемая функция - действие/ожидаемый результат/реальный результат: • предусловия (как привести систему в готовность к тесту) • сценарий действий по переводу системы в новое состояние • постусловия (как откатить систему в предыдущее состояние) • позитивные и негативные сценарии 21 Модульное тестирование Что тестируем • Отдельные модули • классы, наборы функций • А именно, корректность работы: • результат = ожидаемому, • в нужных (и только) случаях генерируются исключения, • или даже происходит останов программы 23 Зачем тестируем • Поиск ошибок в свежем коде • все тесты перед глазами • проще отладка: ошибка локализована в тестовом сценарии • Регрессионное тестирование • со временем рабочий код может ломаться • Test-driven development: • дисциплина: контроль качества • приземлённость: тесты помогают проработать интерфейс 24 Как тестируем • Testing frameworks • Для каждого модуля – свой набор тестов • Фреймворк организует исполнение • запускает тесты • выдаёт отчёт о пройденных/заваленных • Тест содержит проверочные утверждения (assertions) • «завален», если одно из утверждений оказалось неверным 25 Инструменты Инструменты • Фреймворки для модульного тестирования: • • • • JUnit (Java) gtest, Boost Test (C++) NUnit, XUnit (.NET) ***Unit/***Test для большинства других языков/платформ • Автоматическое тестирование интерфейсов: • Selenium – Web-приложения • Sikuli – GUI любых приложений • А также универсальные системы • IBM Rational, TestComplete, и т.п. • Инструменты статического анализа кода 27 Пример: Google C++ Testing Framework (gtest) Подготовка • Фреймворк поставляется в исходных кодах • http://code.google.com/p/googletest/downloads/list • Подготовительные этапы: • получить архив с версией • распаковать • собрать на целевой платформе - в случае MS Visual Studio – проектные файлы в каталоге gtest-x.y.z/msvc • включить в свой проект 29 Подготовка: сборка в MSVS 30 Подготовка: сборка в MSVS 31 Проект с тестами • Создаём новый проект • Добавляем в него путь к gtest/includes • Добавляем зависимости: • Путь до gtest.lib - или gtestd.lib – отладочный • gtest.lib/gtestd.lib в качестве внешней библиотеки • Создаём модули с тестами 32 Проект: include dir 33 Проект: lib dir 34 Проект: библиотека 35 Простой тест •Функция mySqrt • при значениях <0 генерирует исключение • иначе – вычисляет корень •Проверяем: • что исключения действительно генерируются, когда нужно, • и не генерируются, когда не нужно; • что точность вычислений соблюдается 36 Простой тест, часть 1 // MySqrt.h: double mySqrt(double); // TestMySqrt.cpp #include <cmath> #include <float.h> #include "gtest/gtest.h" #include "MySqrt.h" // Tests sqrt of negative numbers. TEST(MySqrtTest, NegativeExcept) { EXPECT_THROW(mySqrt(-1.0), std::exception); EXPECT_THROW(mySqrt(-DBL_MAX), std::exception); } 37 ... Простой тест, часть 2 // TestMySqrt.cpp ... // Tests sqrt on positive TEST(MySqrtTest, PositiveNoExcept) { ASSERT_NO_THROW(mySqrt(2)); ASSERT_NO_THROW(mySqrt(DBL_MAX)); } TEST(MySqrtTest, PositivePrecision) { EXPECT_LT(fabs(1.414213562373 - mySqrt(2)), 1e-6); EXPECT_LT(fabs(1000.0004999 - mySqrt(1000001.)), 1e6); } 38 Запуск тестов // gtest_sample.cpp: #include "gtest/gtest.h" int _tmain(int argc, _TCHAR* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } 39 Сломаем что-нибудь: TEST(MySqrtTest, NegativeExcept) { EXPECT_THROW(mySqrt(1.0), std::exception); EXPECT_THROW(mySqrt(-DBL_MAX), std::exception); } 40 И ещё что-нибудь... TEST(MySqrtTest, PositivePrecision) { EXPECT_LT(fabs(1.414213562373095 - mySqrt(3)), 1e6); } d:\develop\c++\gtest_sample\gtest_sample\testmysqrt.cpp( 23): error: Expected: (fabs(1.414213562373095 mySqrt(3))) < (1e-6), actual: 0.317837 vs 1e-006 41 Базовые утверждения gtest • Логические • ASSERT_TRUE(cond) / EXPECT_TRUE(cond) • ASSERT_FALSE(cond) / EXPECT_FALSE(cond) • Сравнение • _EQ, _NE, _LT, _LE, _GT, _GE • Строки • _STREQ, _STRNE, _STRCASEEQ, _STRCASENE • Исключения • _THROW(statement,exception_type), _ANY_THROW(statement), _NO_THROW(statement) 42 Более сложные тесты • Предварительная подготовка окружения • т.н. fixtures помогают сформировать общее окружение для набора тестов - загрузить данные из файлов - проинициализировать классы/переменные • Замеры времени • Продвинутые проверки (падения, утечки и т.п.) 43 Fixtures • Отличия от простых тестов: • нужно создать класс TestCaseName, потомок testing::Test - метод SetUp инициализация перед тестом - метод TearDown – очистка после теста • тесты объявляются макросом TEST_F (вместо TEST) • всем тестам данного TestCase доступны члены класса TestCaseName 44 Fixtures: пример из gtest Пусть есть класс «очередь»: template <typename ElemType> class Queue { public: Queue(); void Enqueue(const ElemType& element); ElemType* Dequeue(); // NULL if the queue is empty size_t size() const; ... }; 45 Fixtures: пример из gtest class QueueTest : public ::testing::Test { protected: virtual void SetUp() { … } virtual void TearDown() { … } Queue<int> q0_, q1_, q2_; }; 46 Fixtures: пример из gtest class QueueTest : public ::testing::Test { protected: virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } ... } 47 Fixtures: пример из gtest TEST_F(QueueTest, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(NULL, n); … } TEST_F(QueueTest, IsEmptyInitially) { EXPECT_EQ(0, q0_.size()); EXPECT_EQ(1, q1_.size()); } 48 Два сценария одновременно 49 Ссылки • Виды тестирования • http://www.protesting.ru/testing/testtypes.html • http://www.dpgrup.ru/testing.htm • План тестирования: содержимое и образцы • http://www.protesting.ru/testing/plan.html • http://www.softwaretestinghelp.com/test-plan-samplesoftwaretesting-and-quality-assurance-templates/ (англ.) • Модульное тестирование • инструменты: - вики-перечень - JUnit (офсайт – есть “Getting started”) - googletest: сайт, стартовая статья на Хабрахабре • Автоматическое тестирование GUI • http://en.wikipedia.org/wiki/List_of_GUI_testing_tools (Sikuli, Selenium, IBM Rational Functional Tester, SilkTest...) 50