QSpec: тестирование графических приложений на QtКандров Д.Ю., Пушкова Е.А.Unipro
C++ Siberia 2016
Задачи тестирования GUI
Задачей тестирования графического интерфейса пользователя является обнаружение ошибок следующего характера:
● Ошибки в интерфейсе (несоответствие проектной документации, отсутствие элементов интерфейса)
● Ошибки в функциональности посредством интерфейса● Необработанные исключения при взаимодействии с
интерфейсом● Потеря или искажение данных, передаваемых через
элементы интерфейса
Особенности тестирования GUI
● Тест-планы - сценарии, описывающие действия пользователя при работе с системой.
● Сценарии пишут, как правило на естественном языке.
● Выполнение тестов при этом производится либо оператором в ручном режиме, либо системой, которая эмулирует поведение оператора.
● Проверяется внешнее состояние системы, а не значения тех или иных внутренних переменных.
Unipro UGENE*
Проект Unipro UGENE - свободное ПО для работы молекулярного биолога:
● существует 8 лет
● написан на Qt
● более 60 подпроектов (из них 10 - ядро)
● более 4000 функциональных тестов
● более 2000 ручных сценариев (из них ~1200 регрессионных)
* http://ugene.net
Обзор существующих решений
● Squish GUI Tester
● TestComplete
● eggPlant Functional
● AutoIt
● QTest
● QSpec
QTest
● Фреймворк для юнит-тестирования приложений и библиотек на основе Qt
● Есть все функциональные возможности, обычно встречающиеся в фреймворках модульного тестирования
● Имеет расширения для тестирования графического пользовательского интерфейса!
QTest: плюсы
● Поставляется вместе с Qt
● Быстрое создание тестов
● Есть механизм для создания тестов, управляемых данными (DDT)
● Вместо имитации системных событий, Qt Test отправляет внутренние события Qt (нет побочных эффектов от окружения)
QTest: минусы
● Сильно низкоуровневый
● Сложность применения для большого проекта
● Нет менеджера тестов
● Вместо имитации системных событий, Qt Test отправляет внутренние события Qt
QTest: пример плохой ситуации
Тестовое приложение - калькулятор, у которого скрыта кнопка “3”.
Тестовый сценарий:● Сделать 2+3● Проверить, что результат 5
С использованием QTest, тест проходит. Однако, обычный человек его пройти не сможет.
?
QSpec: история создания
Количество сценариев и GUI тестов
QSpec
● Драйвера мыши и клавиатуры для трех систем
● Доступ к объектам осуществляется по QObjectName
● Нет внешнего пускателя тестов
● Логирование через базовые средства Qt
QSpec: Архитектура
QSpec: Архитектура
Использование QSpec: задача
Тестовое приложение - калькулятор.
Тестовый сценарий:
● Сделать 2+3
● Проверить, что результат 5
Сперва проверим есть ли у всех используемых объектов QObjectName и, если нет, то зададим их.
*Этот шаг нужен и при использовании QTest.
display->setObjectName("display");
plusButton->setObjectName("plus");
equalButton->setObjectName("equal");
Использование QSpec: предварительная подготовка*
Использование QSpec: добавляем тест
Создаём файлы с тестами и объявляем наш тест:
#define GUI_TEST_SUITE "Calc_base_tests" TEST_CLASS_DECLARATION(Test1)#undef GUI_TEST_SUITE
Использование QSpec: добавляем тест
Реализуем тест:
TEST_CLASS_DEFINITION(Test1) {
GTWidget::click(os,GTWidget::findButtonByText(os,"2"));
GTWidget::click(os, GTWidget::findWidget(os,"plus"));
GTWidget::click(os, GTWidget::findButtonByText(os,"3"));
GTWidget::click(os, GTWidget::findWidget(os,"equal"));
....
Использование QSpec: добавляем тест
Реализуем тест:
....QLineEdit* display =
qobject_cast<QLineEdit*>(GTWidget::findWidget(os, "display"));
CHECK_SET_ERR(display->text() == "5", "Result is not equal 5");
}
Использование QSpec: регистрируем тест
Регистрируем тест:
class CalcGUITestsLauncher: public GUITestsLauncher {public: CalcGUITestsLauncher();};
CalcGUITestsLauncher::CalcGUITestsLauncher(): GUITestsLauncher(){
guiTestBase.registerTest(new Test1());}
Использование QSpec: пускатель
Делаем запуск в main-е:
QString runGuiTest = qgetenv("HI_GUI_TEST");
if (!runGuiTest.isEmpty()) {CalcGUITestsLauncher* launcher =
new CalcGUITestsLauncher();tests->
connect(&calc,SIGNAL(si_calculatorShowed()), launcher, SLOT(sl_runTest()));
}
Использование QSpec: запуск и результат
Выставляем переменную окружения, чтобы запустить наш тест:export HI_GUI_TEST=Calc_base_tests:Test1
Запускаем калькулятор и видим как он работает без нашего участия.
В консоли видим лог:....GT_DEBUG_MESSAGE Checking condition (display->text() == "5"). Result: OKSuccess
Использование QSpec: ошибки
Если повторить тест со скрытой кнопкой “3”, то получим следующее сообщение в логе:
GT_DEBUG_MESSAGE Checking condition(display->text() == "5"). Result: FAILED
GT_DEBUG_MESSAGE errorMessage 'result is not equal 5'
QSpec: плюсы
● Честная имитация системных событий на трёх основных ОС
● Быстрое создание тестов
● Достаточно высокоуровневый интерфейс для работы с примитивами Qt
● Открытый проект
QSpec: минусы
● Честная имитация системных событий - тесты сильно зависят от стабильности окружения
● Нет менеджера тестов
● Перегруженное логирование
Планы по развитию проекта
● Пускатель тестов● Генератор тестов● Улучшение логирования
○ добавить уровни логирования○ поддержать разные форматы вывода, чтобы их
понимали CI (например TeamCity)○ возможно встроить уже готовый логгер
● Такой интерфейс, чтобы легко можно было подменить QTest и посмотреть результаты тестового прогона на QSpec
● TDD, на основе Cucumber (совсем светлое будущее)
Спасибо за внимание!Ваши вопросы?
Адрес проекта: https://github.com/ugeneunipro/QSpec