Тестирование в компании  Дмитрий Зенович
Начальные условия Десятки типов онлайн демонов на C++ Десятки  offline  скриптов на  PHP  и демонов на C++ веб-интерфейс API генераторы статистики и отчетов Объем кода – несколько сотен тысяч строк
Начальные условия Что хотелось сделать: •  сократить время итерации и увеличить продуктивность разработки •  создать отдел тестирования (тестирование проводилось силами разработчиков) •  увеличить полноту документации •  оптимизировать процесс внедрения в  PHP -разработке
Часть 1 Тестирование
Начало тестирования Ставка на  автоматизированное тестирование . Выбор в качестве фреймворка для автоматизированного тестирования  PHPUnit Стандарты кодирования . Один класс в файле. Мэппинг имени класса в имя файла. Непрерывный рефакторинг. Переписывать все непонятное, упрощать все сложное, избавляться от дублирования.
Библиотека  / ConfigurableObject Testlib_ConfigurableObject Эмуляция массива (доступ по индексу для свойств) Свойства  типизированы /** * HTTP-method * @var string */ public   $method   =   'GET' ;   Конструктор принимает на вход массив со значениями свойств
Библиотека  / ConfigurableObject Защищенные свойства /** * @property * @var string */ protected  $readOnly ; protected  function  _setReadOnly ( $value )   { throw … } protected  function  _getReadOnly ()   {   return   1 ;   }
Библиотека  / ConfigurableObject Сериализация :  toArray() ,  __toString() Сериализация в XML @serializeXmlAs  node(имя)|attribute|text|cdata|none   @serializeXmlAs  node( имя ) в  заголовке класса $obj  =  Testlib_ConfigurableObject :: fromXml ( 'XmlObj' , $xmlString ) ; $obj-> to Xml ( )  ; Другие виды сериализации Внутренние  форматы  сериализации, JSON,  HTML , …
Библиотека  / ConfigurableObject /** * @serializeXmlAs node(begun) */ class  Testlib_Client_Daemon_Response_Banner_Body_Begun  extends  Testlib_ConfigurableObject   { /** * @var  Testlib_Client_Daemon_Response_Banner_Body_Begun_Banner [] */ public  $banner   =   array () ; } $obj   =   Testlib_ConfigurableObject :: fromXml ( ' Testlib_Client_Daemon_Response_Banner_Body_Begun ' ,   $data ) ;
Библиотека  / MethodMock Testlib_MethodMock Изоляция тестируемого функционала Предотвращение лишних действий Предотвращение долгих операций в тестах (БД и т.п.) Упрощение подготовки начальной конфигурации PECL- модуль   runkit  (runkit_method_copy, runkit_method_redefine, runkit_method_remove, …) Перехват встроенных функций PHP Патчи  runkit
Библиотека  / MethodMock $ m 1   =   Testlib_MethodMock :: interceptMethodByCode ( "MyClass" , "myMethod" ,   "echo ' 1 ';" ) ; $ m2   =  Testlib_MethodMock :: mockFunctionResult ( 'getValue' , 12345 ,   array ( 2 , 1 )) ; $ m3   =  Testlib_MethodMock :: interceptMethodByCode ( "MyClass" , "myMethod" ,   "echo 'called';" ) ; $ m1 -> getCalledArgs () ; $ m2 -> getCalledResults () ; $ m3 -> isCalled () ; $ m1 -> countCalled () ; $m 2 -> resetCallStack () ; $m 3 -> revert () ;
Библиотека  / TcpdumpCatcher Testlib_TcpdumpCatcher $catcher   =   new  Testlib_TcpdumpCatcher ( TESTLAB_HOST ,  TESTLAB_USER ,   TESTLAB_PASS ,   "192.168.1.3" ,   "8080" ,   "eth0" ) ; // ... $dump   =   $catcher -> finish () ; Внутри:  tcpdump , анализ собранных пакетов, склеивание с учетом фрагментирования, парсинг Работает локально или удаленно
Библиотека  / LogCatcher Testlib_LogCatcher $catcher   =   new  Testlib_LogCatcher ( "my.log" ,   /* "192.168.1.3" ,   "myuser" ,   "123456“ */ ) ; // ...   $log   =   $catcher -> finish () ; Внутри:  wc -l , tail -n  Работает локально или удаленно
Работа с базой данных MySQL, транзакционность InnoDB, реализация вложенных транзакций Testlib _ TestDb Zend_Db   реализация вложенных транзакций фабрика на основе конфигураций остановка/восстановление репликации Очистка по расписанию
Библиотека  / DatabaseMock Testlib_DatabaseMock $dbMock   =  new Testlib_DatabaseMock ( 'Cards' ,   'CardsForTest' , false ,   array ( 'CatalogTree' ,   'CatalogInfo' )) ;   //  ... $dbMock -> revert () ;   Внутри : Testlib_MethodMock::interceptFunction('mysql_query'); runkit_constant_redefine (…) Различные способы экранирования имен таблиц и баз учитываются
Библиотека  / DbiCleaner Testlib_D biCleaner $id   =  …  Testlib_DbiCleaner :: add ( 'DbName.tableName' ,   'id' ,   $id ) ; //  ...   Testlib_DbiCleaner :: start () ; Есть также очистка из командной строки
Библиотека  / FakeDaemon Testlib_ FakeDaemon Подмена ответов.  nginx + php.  Настройка  ini- файла: [:7099] serviceNam e="4test" port =80 host ="lab128" logfile ="./7099-4tests.log " Подмена ответа: Testlib_FakeDaemon :: setCustomResponse ( '4test' , $requestText , $responseText ) ;
Библиотека  / FakeDaemon $ responseText  может не содержать  HTTP -заголовков $requestText может быть  неполным  текстом запроса Внутри   подмены : Testlib_FakeDeamon_CustomResponse::fromRequestAndResponse() Создаются условия по  requestMethod ,  handler , каждому  get -параметру , по каждому  заголовку , кроме « Host ».  Порядок полей не важен. Ответ и его условия сохраняются в базу и заносятся в DbiCleaner
Библиотека  / FakeDaemon Обработка запроса Определение конфигурации по порту Получение всех подмененных запросов для сервиса (в обратном порядке) Для каждой подмены проверяются условия ( И ,  urldecode  для get-параметров) Если подмена найдена, то возвращается она, иначе ответ ищется в  кэш , если там нет, то берется ответ настоящего демона. Позволяет тестировать программы независимо! Тест должен очищать после себя подмены.
Создание клиента  daemon’ а Базовый класс ( Testlib_ClientTest ) Работа с  конфигом  демона в БД (получение, изменение) Абстрактный  http- запрос  к демону Абстрактный  http-запрос  к демону  для тестов  ( конфиг, лог, подмена ответов других демонов,  TcpdumpCatcher , контроль изоляции демона, поиск ошибок в логе) Запуск и остановка демона , запущен ли демон, ожидание запуска requestHandler , requestHandlerForTests   ( Testlib_ConfigurableObject )
Создание клиента  daemon’ а Новый клиент Создаем новый класс ;  прописываем в свойствах   имя демона, таблицу с конфигом, «нижние» демона ;  реализуем методы для каждого хэндлера : /** * @param mixed<Testlib_Client_Daemon_RequestParamsForTests_Index> $params * @return Testlib_Client_Daemon_ResponseForTests_ Index */ public static function requestIndexForTests ( $params   =   array ())   { return  self :: requestHandlerForTests ( 'index' ,   $params ) ; } создаем классы ( Testlib _ ConfigurableObject ) для входных и выходных данных хэндлеров
Создание клиента  daemon’ а Написание тестов демонов $params   =   array ( 'params'   =>  array (   'getParams'   =>   array ( ... ) ,  ... ) , 'tcpdump'   =>   array ( ... ) , 'customResponses'   =>   array ( Testlib_FakeDaemon_CustomResponse :: fromRequestAndResponse ( 'subdaemon' ,   '/handler' ,   ( string )   (string)  new   Testlib_Client_Subdaemon_Response_Handler_Body ( ... ) ) ,   ... ) ) ; $result   =  Testlib_Client_Daemon :: requestIndexForTests ( $params ) ;
Библиотека Базовые классы тестов и сьютов демонов Testlib _ TestSuite  остановка и возобновление репликации prepare/clean up CommonSuite  (много тестов для одного запроса к демону)
Тестирование  PHP Можно использовать библиотеки PHP-разработчиков Методы белого ящика Написание юнит-тестов PHP Базовый   кла c с  Testlib_TestCase_Php Блокирование коммита  БД C тарт транзакции в setUp, откат в  tearDown Очистка глобальных объектов Список sql-запросов в отчетах об ошибке Отслеживание коммитов и роллбэков Проблема  parent::setUp  и  parent::tearDown
Тестирование  PHP Testlib_ScriptRunner Возвращать результат, вывод,  log  скрипта Умеет дожидаться освобождения  lock -файла run S cript () runScriptByIncluding () удаляет константы, определенные в скрипте удаляет функции, определенные в скрипте неправильное окружение, зато есть возможность подменять методы, базы, откатывать   транзакцию
Тестирование  web- интерфейса Доработки PHPUnit в части работы с  Selenium Более подробный отчет об ошибке Добавлены: URL  страницы,  скриншот , HTML- source ,  история команд   Selenium , лог запросов  БД , отчет об ошибке в формате  HTML Переписан драйвер работы с Selenium-RC Исправление  HTTP ( Ускорение  > 10 раз) Перекодировка запросов и ответов Отмена автоматического закрытия окна браузера при ошибках
Тестирование  web- интерфейса Общий подход:  Testlib _ TestCase _ Selenium , ускорение авторизации Использовать Selenium как можно меньше!   Удаленный перехват методов и функций  PHP Оболочка MethodMock для  удаленного перехвата . Принцип работы: sessionId, Zend_Cache
Тестирование  JavaScript Testlib_TestCase_J sBlock Подмена в браузере настраиваемый прокси для подмены ответов демонов и статических файлов веб-нитерфейс для управлениями правилами
Виртуальные стенды Однопоточность тестов Переменные состояния программ Общие объекты базы данных (один тест меняет конфигурацию других) Общие динамические файлы на файловой системе Lock wait-timeout базы TcpdumpCatcher lock- и log-файлы D bi Cleaner FakeDaemon (чужие ответы) Замедление тестов из-за сети, сложность поддержки распределенной с-мы.
Виртуальные стенды Для каждого потока тестов должны быть свои: тестируемая программа база данных динамические каталоги сетевые порты/хосты для хождения к другим программам по сети каталоги с  log - и  lock -файлами Желательно, чтобы все это было на одной машине Переносим все в тестовый стенд!
Виртуальные стенды Виртуальный компьютер на основе xen Создание нового стенда : php /begun/www/teststand/createLab.php --daemon=<daemon> [--start] [--swap] Для каждой программы своя конфигурация (по <daemon>): Базы данных и таблицы (с данными и без) Скрипт для установки тестируемой программы и зависимостей Скрипт для запуска тестируемой программы и зависимостей При создании стенда также делается checkout тестов, тестовых библиотек и утилит
Виртуальные стенды Список виртуальных машин: xm list Остановка/восстановление: xm start/destroy Удаление: php  / begun / www / teststand / deleteLab . php Важно: база данных должна содержать только минимальный набор данных, необходимых для работы программы и тестов.
Непрерывная интеграция phpUnderControl. Стадии билда: Создаем новый стенд Компилируем тестируемую программу (C++) Устанавливаем скомпилированную программу на стенд ( C ++) Обновляем/выкачиваем код программы (PHP) Обновляем/выкачиваем тесты и тестовые библиотеки Прогоняем тесты Удаляем тестовый стенд Билды запускаются автоматически (интервал времени/модификация кода) Отчет формируется автоматически
Непрерывная интеграция Что запускать непрерывно: тесты стабильной ветки, которые не прогоняются перед выкладкой тесты которые запускаются редко (текущая ветка и т.п.) все «маленькое», что очень лень запускать вручную Бонусы: степень покрытия кода тестами возможность автоматической генерации документации выявление проблем кода (стандарты кодирования, кол-во методов в классе, кол-во строк в методе, сложность кода, …)
Конец первой части
Часть 2 Нагрузочное тестирование
Нагрузочное тестирование Минусы тестовой среды: - Проблематичность создания адекватной нагрузки - Трудности в повторении среды production (железо, сеть, …) - Необходимость в интегральном подходе (связанные демона и базы) - Необходимость в системах мониторинга - Необходимость в специалистах по нагрузочному тестированию После функционального тестирования задача передается в нагрузочное тестирование.
Нагрузочное тестирование Инструмент для дублирования трафика Безопасно дублирует production запросы (%) Динамическое включение, выключение, перенацеливание Гибкое управление долей дублированного трафика (от 0% до N*100%) Настраивается через  web -интерфейс
Нагрузочное тестирование Тестирование новых версий Выведение машины из production Установка на машину новой версии Дублирование трафика с production-машины (%) Мониторинг нагрузки на подсистемы самой машины (диск, CPU, сеть) и времени ответа Мониторинг логов тестируемого демона Оценивается динамика нагрузки на «нижние» подсистемы
Нагрузочное тестирование Стресс-тестирование старых версий Постепенное увеличение нагрузки (>100%) Мониторинг кол-ва ошибочных ответов и времени ответа Мониторинг нагрузки на подсистемы самой машины (диск, CPU, сеть) и времени ответа Мониторинг логов тестируемого демона Мониторинг нагрузки на failover-машину Изучение логов балансера (время ответа) Комплексная оценка производительности
Конец второй части
Часть 3 Эпилог
Тестирование улучшает климат код на  production  точно совпадает с кодом в стабильной ветке утверждены стандарты кодирования (PHP) новый/измененный код покрывается юнит-тестами ( PHP ) введена процедура code-review перед коммитом в стабильную ветку прогоняются тесты подробные описания проектов в  wiki подробные описания задач в тикетах введены обязательные декомпозиции разработки и тестирования с оценкой трудозатрат месячные   планы
Результаты и будущее  Подробная документация Внедрение проверенного кода Стабильная и предсказуемая разработка Выполнение месячных планов Сбор и анализ формализованных отчетов об ошибке
Ссылки +  литература PHP: http:// php.net / PHPUnit: http:// phpunit.de /   phpUnderControl: http:// phpundercontrol.org / Selenium: http :// seleniumhq.org / runkit: http:// pecl.php.net/package/runkit Extending and Embedding PHP by Sara Golemon Мессарош, Дж. Шаблоны тестирования xUnit: рефакторинг кода тестов (XUnit Test Patterns: Refactoring Test Code) Дастин, Э. Автоматизированное тестирование программного обеспечения: пер. с англ. / Э. Дастин, Дж. Рэшка, Дж. Пол
СПАСИБО! Дмитрий Зенович, руководитель отдела тестирования E-mail:  dzenovich@ begun.ru

бегун

  • 1.
    Тестирование в компании Дмитрий Зенович
  • 2.
    Начальные условия Десяткитипов онлайн демонов на C++ Десятки offline скриптов на PHP и демонов на C++ веб-интерфейс API генераторы статистики и отчетов Объем кода – несколько сотен тысяч строк
  • 3.
    Начальные условия Чтохотелось сделать: • сократить время итерации и увеличить продуктивность разработки • создать отдел тестирования (тестирование проводилось силами разработчиков) • увеличить полноту документации • оптимизировать процесс внедрения в PHP -разработке
  • 4.
  • 5.
    Начало тестирования Ставкана автоматизированное тестирование . Выбор в качестве фреймворка для автоматизированного тестирования PHPUnit Стандарты кодирования . Один класс в файле. Мэппинг имени класса в имя файла. Непрерывный рефакторинг. Переписывать все непонятное, упрощать все сложное, избавляться от дублирования.
  • 6.
    Библиотека /ConfigurableObject Testlib_ConfigurableObject Эмуляция массива (доступ по индексу для свойств) Свойства типизированы /** * HTTP-method * @var string */ public $method = 'GET' ; Конструктор принимает на вход массив со значениями свойств
  • 7.
    Библиотека /ConfigurableObject Защищенные свойства /** * @property * @var string */ protected $readOnly ; protected function _setReadOnly ( $value ) { throw … } protected function _getReadOnly () { return 1 ; }
  • 8.
    Библиотека /ConfigurableObject Сериализация : toArray() , __toString() Сериализация в XML @serializeXmlAs node(имя)|attribute|text|cdata|none @serializeXmlAs node( имя ) в заголовке класса $obj = Testlib_ConfigurableObject :: fromXml ( 'XmlObj' , $xmlString ) ; $obj-> to Xml ( ) ; Другие виды сериализации Внутренние форматы сериализации, JSON, HTML , …
  • 9.
    Библиотека /ConfigurableObject /** * @serializeXmlAs node(begun) */ class Testlib_Client_Daemon_Response_Banner_Body_Begun extends Testlib_ConfigurableObject { /** * @var Testlib_Client_Daemon_Response_Banner_Body_Begun_Banner [] */ public $banner = array () ; } $obj = Testlib_ConfigurableObject :: fromXml ( ' Testlib_Client_Daemon_Response_Banner_Body_Begun ' , $data ) ;
  • 10.
    Библиотека /MethodMock Testlib_MethodMock Изоляция тестируемого функционала Предотвращение лишних действий Предотвращение долгих операций в тестах (БД и т.п.) Упрощение подготовки начальной конфигурации PECL- модуль runkit (runkit_method_copy, runkit_method_redefine, runkit_method_remove, …) Перехват встроенных функций PHP Патчи runkit
  • 11.
    Библиотека /MethodMock $ m 1 = Testlib_MethodMock :: interceptMethodByCode ( &quot;MyClass&quot; , &quot;myMethod&quot; , &quot;echo ' 1 ';&quot; ) ; $ m2 = Testlib_MethodMock :: mockFunctionResult ( 'getValue' , 12345 , array ( 2 , 1 )) ; $ m3 = Testlib_MethodMock :: interceptMethodByCode ( &quot;MyClass&quot; , &quot;myMethod&quot; , &quot;echo 'called';&quot; ) ; $ m1 -> getCalledArgs () ; $ m2 -> getCalledResults () ; $ m3 -> isCalled () ; $ m1 -> countCalled () ; $m 2 -> resetCallStack () ; $m 3 -> revert () ;
  • 12.
    Библиотека /TcpdumpCatcher Testlib_TcpdumpCatcher $catcher = new Testlib_TcpdumpCatcher ( TESTLAB_HOST , TESTLAB_USER , TESTLAB_PASS , &quot;192.168.1.3&quot; , &quot;8080&quot; , &quot;eth0&quot; ) ; // ... $dump = $catcher -> finish () ; Внутри: tcpdump , анализ собранных пакетов, склеивание с учетом фрагментирования, парсинг Работает локально или удаленно
  • 13.
    Библиотека /LogCatcher Testlib_LogCatcher $catcher = new Testlib_LogCatcher ( &quot;my.log&quot; , /* &quot;192.168.1.3&quot; , &quot;myuser&quot; , &quot;123456“ */ ) ; // ... $log = $catcher -> finish () ; Внутри: wc -l , tail -n Работает локально или удаленно
  • 14.
    Работа с базойданных MySQL, транзакционность InnoDB, реализация вложенных транзакций Testlib _ TestDb Zend_Db реализация вложенных транзакций фабрика на основе конфигураций остановка/восстановление репликации Очистка по расписанию
  • 15.
    Библиотека /DatabaseMock Testlib_DatabaseMock $dbMock = new Testlib_DatabaseMock ( 'Cards' , 'CardsForTest' , false , array ( 'CatalogTree' , 'CatalogInfo' )) ; // ... $dbMock -> revert () ; Внутри : Testlib_MethodMock::interceptFunction('mysql_query'); runkit_constant_redefine (…) Различные способы экранирования имен таблиц и баз учитываются
  • 16.
    Библиотека /DbiCleaner Testlib_D biCleaner $id = … Testlib_DbiCleaner :: add ( 'DbName.tableName' , 'id' , $id ) ; // ... Testlib_DbiCleaner :: start () ; Есть также очистка из командной строки
  • 17.
    Библиотека /FakeDaemon Testlib_ FakeDaemon Подмена ответов. nginx + php. Настройка ini- файла: [:7099] serviceNam e=&quot;4test&quot; port =80 host =&quot;lab128&quot; logfile =&quot;./7099-4tests.log &quot; Подмена ответа: Testlib_FakeDaemon :: setCustomResponse ( '4test' , $requestText , $responseText ) ;
  • 18.
    Библиотека /FakeDaemon $ responseText может не содержать HTTP -заголовков $requestText может быть неполным текстом запроса Внутри подмены : Testlib_FakeDeamon_CustomResponse::fromRequestAndResponse() Создаются условия по requestMethod , handler , каждому get -параметру , по каждому заголовку , кроме « Host ». Порядок полей не важен. Ответ и его условия сохраняются в базу и заносятся в DbiCleaner
  • 19.
    Библиотека /FakeDaemon Обработка запроса Определение конфигурации по порту Получение всех подмененных запросов для сервиса (в обратном порядке) Для каждой подмены проверяются условия ( И , urldecode для get-параметров) Если подмена найдена, то возвращается она, иначе ответ ищется в кэш , если там нет, то берется ответ настоящего демона. Позволяет тестировать программы независимо! Тест должен очищать после себя подмены.
  • 20.
    Создание клиента daemon’ а Базовый класс ( Testlib_ClientTest ) Работа с конфигом демона в БД (получение, изменение) Абстрактный http- запрос к демону Абстрактный http-запрос к демону для тестов ( конфиг, лог, подмена ответов других демонов, TcpdumpCatcher , контроль изоляции демона, поиск ошибок в логе) Запуск и остановка демона , запущен ли демон, ожидание запуска requestHandler , requestHandlerForTests ( Testlib_ConfigurableObject )
  • 21.
    Создание клиента daemon’ а Новый клиент Создаем новый класс ; прописываем в свойствах имя демона, таблицу с конфигом, «нижние» демона ; реализуем методы для каждого хэндлера : /** * @param mixed<Testlib_Client_Daemon_RequestParamsForTests_Index> $params * @return Testlib_Client_Daemon_ResponseForTests_ Index */ public static function requestIndexForTests ( $params = array ()) { return self :: requestHandlerForTests ( 'index' , $params ) ; } создаем классы ( Testlib _ ConfigurableObject ) для входных и выходных данных хэндлеров
  • 22.
    Создание клиента daemon’ а Написание тестов демонов $params = array ( 'params' => array ( 'getParams' => array ( ... ) , ... ) , 'tcpdump' => array ( ... ) , 'customResponses' => array ( Testlib_FakeDaemon_CustomResponse :: fromRequestAndResponse ( 'subdaemon' , '/handler' , ( string ) (string) new Testlib_Client_Subdaemon_Response_Handler_Body ( ... ) ) , ... ) ) ; $result = Testlib_Client_Daemon :: requestIndexForTests ( $params ) ;
  • 23.
    Библиотека Базовые классытестов и сьютов демонов Testlib _ TestSuite остановка и возобновление репликации prepare/clean up CommonSuite (много тестов для одного запроса к демону)
  • 24.
    Тестирование PHPМожно использовать библиотеки PHP-разработчиков Методы белого ящика Написание юнит-тестов PHP Базовый кла c с Testlib_TestCase_Php Блокирование коммита БД C тарт транзакции в setUp, откат в tearDown Очистка глобальных объектов Список sql-запросов в отчетах об ошибке Отслеживание коммитов и роллбэков Проблема parent::setUp и parent::tearDown
  • 25.
    Тестирование PHPTestlib_ScriptRunner Возвращать результат, вывод, log скрипта Умеет дожидаться освобождения lock -файла run S cript () runScriptByIncluding () удаляет константы, определенные в скрипте удаляет функции, определенные в скрипте неправильное окружение, зато есть возможность подменять методы, базы, откатывать транзакцию
  • 26.
    Тестирование web-интерфейса Доработки PHPUnit в части работы с Selenium Более подробный отчет об ошибке Добавлены: URL страницы, скриншот , HTML- source , история команд Selenium , лог запросов БД , отчет об ошибке в формате HTML Переписан драйвер работы с Selenium-RC Исправление HTTP ( Ускорение > 10 раз) Перекодировка запросов и ответов Отмена автоматического закрытия окна браузера при ошибках
  • 27.
    Тестирование web-интерфейса Общий подход: Testlib _ TestCase _ Selenium , ускорение авторизации Использовать Selenium как можно меньше!  Удаленный перехват методов и функций PHP Оболочка MethodMock для удаленного перехвата . Принцип работы: sessionId, Zend_Cache
  • 28.
    Тестирование JavaScriptTestlib_TestCase_J sBlock Подмена в браузере настраиваемый прокси для подмены ответов демонов и статических файлов веб-нитерфейс для управлениями правилами
  • 29.
    Виртуальные стенды Однопоточностьтестов Переменные состояния программ Общие объекты базы данных (один тест меняет конфигурацию других) Общие динамические файлы на файловой системе Lock wait-timeout базы TcpdumpCatcher lock- и log-файлы D bi Cleaner FakeDaemon (чужие ответы) Замедление тестов из-за сети, сложность поддержки распределенной с-мы.
  • 30.
    Виртуальные стенды Длякаждого потока тестов должны быть свои: тестируемая программа база данных динамические каталоги сетевые порты/хосты для хождения к другим программам по сети каталоги с log - и lock -файлами Желательно, чтобы все это было на одной машине Переносим все в тестовый стенд!
  • 31.
    Виртуальные стенды Виртуальныйкомпьютер на основе xen Создание нового стенда : php /begun/www/teststand/createLab.php --daemon=<daemon> [--start] [--swap] Для каждой программы своя конфигурация (по <daemon>): Базы данных и таблицы (с данными и без) Скрипт для установки тестируемой программы и зависимостей Скрипт для запуска тестируемой программы и зависимостей При создании стенда также делается checkout тестов, тестовых библиотек и утилит
  • 32.
    Виртуальные стенды Списоквиртуальных машин: xm list Остановка/восстановление: xm start/destroy Удаление: php / begun / www / teststand / deleteLab . php Важно: база данных должна содержать только минимальный набор данных, необходимых для работы программы и тестов.
  • 33.
    Непрерывная интеграция phpUnderControl.Стадии билда: Создаем новый стенд Компилируем тестируемую программу (C++) Устанавливаем скомпилированную программу на стенд ( C ++) Обновляем/выкачиваем код программы (PHP) Обновляем/выкачиваем тесты и тестовые библиотеки Прогоняем тесты Удаляем тестовый стенд Билды запускаются автоматически (интервал времени/модификация кода) Отчет формируется автоматически
  • 34.
    Непрерывная интеграция Чтозапускать непрерывно: тесты стабильной ветки, которые не прогоняются перед выкладкой тесты которые запускаются редко (текущая ветка и т.п.) все «маленькое», что очень лень запускать вручную Бонусы: степень покрытия кода тестами возможность автоматической генерации документации выявление проблем кода (стандарты кодирования, кол-во методов в классе, кол-во строк в методе, сложность кода, …)
  • 35.
  • 36.
    Часть 2 Нагрузочноетестирование
  • 37.
    Нагрузочное тестирование Минусытестовой среды: - Проблематичность создания адекватной нагрузки - Трудности в повторении среды production (железо, сеть, …) - Необходимость в интегральном подходе (связанные демона и базы) - Необходимость в системах мониторинга - Необходимость в специалистах по нагрузочному тестированию После функционального тестирования задача передается в нагрузочное тестирование.
  • 38.
    Нагрузочное тестирование Инструментдля дублирования трафика Безопасно дублирует production запросы (%) Динамическое включение, выключение, перенацеливание Гибкое управление долей дублированного трафика (от 0% до N*100%) Настраивается через web -интерфейс
  • 39.
    Нагрузочное тестирование Тестированиеновых версий Выведение машины из production Установка на машину новой версии Дублирование трафика с production-машины (%) Мониторинг нагрузки на подсистемы самой машины (диск, CPU, сеть) и времени ответа Мониторинг логов тестируемого демона Оценивается динамика нагрузки на «нижние» подсистемы
  • 40.
    Нагрузочное тестирование Стресс-тестированиестарых версий Постепенное увеличение нагрузки (>100%) Мониторинг кол-ва ошибочных ответов и времени ответа Мониторинг нагрузки на подсистемы самой машины (диск, CPU, сеть) и времени ответа Мониторинг логов тестируемого демона Мониторинг нагрузки на failover-машину Изучение логов балансера (время ответа) Комплексная оценка производительности
  • 41.
  • 42.
  • 43.
    Тестирование улучшает климаткод на production точно совпадает с кодом в стабильной ветке утверждены стандарты кодирования (PHP) новый/измененный код покрывается юнит-тестами ( PHP ) введена процедура code-review перед коммитом в стабильную ветку прогоняются тесты подробные описания проектов в wiki подробные описания задач в тикетах введены обязательные декомпозиции разработки и тестирования с оценкой трудозатрат месячные планы
  • 44.
    Результаты и будущее Подробная документация Внедрение проверенного кода Стабильная и предсказуемая разработка Выполнение месячных планов Сбор и анализ формализованных отчетов об ошибке
  • 45.
    Ссылки + литература PHP: http:// php.net / PHPUnit: http:// phpunit.de / phpUnderControl: http:// phpundercontrol.org / Selenium: http :// seleniumhq.org / runkit: http:// pecl.php.net/package/runkit Extending and Embedding PHP by Sara Golemon Мессарош, Дж. Шаблоны тестирования xUnit: рефакторинг кода тестов (XUnit Test Patterns: Refactoring Test Code) Дастин, Э. Автоматизированное тестирование программного обеспечения: пер. с англ. / Э. Дастин, Дж. Рэшка, Дж. Пол
  • 46.
    СПАСИБО! Дмитрий Зенович,руководитель отдела тестирования E-mail: dzenovich@ begun.ru