Пятница, 19.04.2024, 19:35 Приветствую Вас Гость

Quick Soft

Главная | Мой профиль | Форум | Загрузки | RSS | Выход

Разработка тестов

Все тестовые методы должны быть слотами, а и их наименование должно начинаться с префикса test_, так как движку модульного тестирования нужно отделять обычные слоты, от тестовых слотов. Под обычными слотами понимаются слоты, используемые для обработки сигналов сторонних объектов, участвующих в тестировании. Так же для сокращения декларативной части тестового класса, нами было принято решение о внесении параметров — атрибутов тестовых слотов непосредственно в их наименование (аналогично использованию префикса test_ ). Что позволит быстро менять параметры тестового метода. Например:

Пример указания атрибутов для тестового слота
  1. #ifndef MYTEST_H
  2. #define MYTEST_H
  3.  
  4. #include <QS_QuickUnit.h>
  5.  
  6. class MyTest : public QS_TestClass
  7. {
  8.     Q_OBJECT
  9.  
  10.         private slots:
  11.  
  12.             void test_myTest_Fatal_Repiat_15()
  13.             {
  14.                 QS_BEGIN_TEST;
  15.  
  16.                 //реализуем логику тестирования
  17.                 QS_END_TEST;
  18.                 QS_TEST_COMPLETE;
  19.             }
  20. };
  21.  
  22. #endif //MYTEST_H

элементы _Fatal и _Repiat_15 в наименовании тестового слота , являются атрибутами. Задача атрибута — указать системе, что слот должен выполняться с некоторыми особенностями. К примеру, указать системе, что слот надо выполнить повторно n - раз. В текущей версии реализовано пока только два атрибута. Далее список будет расширен.

Поскольку все тесты являются асинхронными, то за момент завершения теста отвечает уже разработчик. Что бы указать системе, что тест завершен - необходимо использовать макрос QS_TEST_COMPLETE. Его задача указать системе что, тест пройден успешно и можно переходить к следующему. В случае если вы забудете указать системе факт завершения, то тест никогда не завершиться (в будущей версии планируется timeout для таких ситуаций). Так же, для обработки возникающих исключений, реализовано два макроса QS_BEGIN_TEST и QS_END_TEST. Они представляют собой не что иное, как блок try catch. В блоке catch происходит завершение теста с указанием, что он завершен аварийно.

Рассмотрим чуть более сложный пример, раскрывающий, что же такое асинхронное тестирование на практике. Мы напишем тест, который будет тестировать загрузку веб странички с помощью QWebView.

Пример асинхронного модульного теста
  1. #ifndef QS_WEBKIT_TEST_H
  2. #define QS_WEBKIT_TEST_H
  3.  
  4. #include <QS_QuickUnit.h>
  5. #include <QtWebKit>
  6.  
  7. class QS_WebKit : public QS_TestClass
  8. {
  9.     Q_OBJECT
  10.  
  11.         private slots:
  12.  
  13.             void test_LoadWebPage()
  14.             {
  15.                 QS_BEGIN_TEST;
  16.  
  17.                 m_pView = new QWebView( 0 );
  18.  
  19.                 connect( m_pView,
  20.                          SIGNAL( loadFinished( bool ) ),
  21.                          SLOT( slot_loadFinished( bool ) ) );
  22.  
  23.                 m_pView->load( QUrl( "http://www.google.ru" ) );
  24.  
  25.                 QS_END_TEST;
  26.             }//по выходу из функции тест не завершается!
  27.  
  28.             void slot_loadFinished ( bool ok )
  29.             {
  30.                 QS_BEGIN_TEST;
  31.  
  32.                 //проверяем результат
  33.                 QS_IS_TRUE( ok );
  34.                 QS_IS_TRUE( m_pView->page()->totalBytes() > 100 );
  35.  
  36.                 QS_END_TEST;
  37.                 QS_TEST_COMPLETE;//Указываем, что тест завершен успешно
  38.             }
  39. };
  40.  
  41. #endif //QS_WEBKIT_TEST_H

Как видно из примера, теперь можно тестировать любые асинхронные операции. Особо хочу обратить внимание, что все тестовые слоты выполняются в контексте основного потока приложения, что позволяет свободно использовать виджеты, COM объекты и прочие объекты которые могут быть созданы только в контексте основного потока. Система полностью совместима с MFC, ATL и Win32, что позволяет вам использовать ее не только для QT.

Для оптимизации тестирующего кода, введены еще дополнительно 4 системных слота, все эти слоты являются критическими (по умолчанию имеют атрибут _Fatal):

void StartTestClass();
вызывается перед запуском тестового класса, используется для инициализации объектов класса, вызывается один раз в рамках своего класса;
void CompleteTestClass( … );
вызывается по прохождении всех тестовых слотов, и используется для освобождения всех ресурсов занятых слотом void StartTestClass();
void StartTestMethod( … );
вызывается системой перед запуском каждого тестового слота, используется для инициализации необходимых объектов для конкретного тестового случая;
void CompleteTestMethod( … );
вызывается системой по завершении каждого тестового слота, используется для освобождения занятых ресурсов;


Рассмотрим пример использования некоторых из них.

Пример использования служебных слотов
  1. #ifndef QS_WEBKIT_H
  2. #define QS_WEBKIT_H
  3.  
  4. #include <QS_QuickUnit.h>
  5. #include <QtWebKit>
  6. #include <QUrl>
  7.  
  8. class QS_WebKit : public QS_TestClass
  9. {
  10.     Q_OBJECT
  11.  
  12. private:
  13.  
  14.     QWebView * m_pView;
  15.  
  16. protected slots:
  17.  
  18.      /* Перед запуском тестового слота, создаем объект,
  19.      * соединяем сигналы и слоты
  20.      */
  21.      void StartTestMethod( QString strTestMethodName )
  22.      {
  23.          QS_BEGIN_TEST;
  24.  
  25.          m_pView = new QWebView( 0 );
  26.  
  27.          QS_IS_TRUE( connect( m_pView,
  28.                               SIGNAL( loadFinished( bool ) ),
  29.                               SLOT( slot_loadFinished( bool ) ) ) );
  30.  
  31.          QS_END_TEST;
  32.          QS_TEST_COMPLETE;
  33.      }
  34.  
  35.      /* после завершения тестового слота удаляем объект
  36.      */
  37.      void CompleteTestMethod( QString strTestMethodName, QS_TestResult eResult )
  38.      {
  39.          QS_BEGIN_TEST
  40.  
  41.          delete m_pView;
  42.          m_pView = 0;
  43.  
  44.          QS_END_TEST;
  45.          QS_TEST_COMPLETE;
  46.      }
  47.      
  48. private slots:
  49.  
  50.      //теперь объем стал меньше, и можно сфокусироваться на тестировании
  51.      void test_LoadWebPage()
  52.      {
  53.          QS_BEGIN_TEST;
  54.  
  55.          m_pView->load( QUrl( "http://www.google.ru" ) );
  56.  
  57.          QS_END_TEST;
  58.      }
  59.  
  60.      //сигнал от браузера
  61.      void slot_loadFinished ( bool ok )
  62.      {
  63.          QS_BEGIN_TEST;
  64.  
  65.          //проверяем результат
  66.          QS_IS_TRUE( ok );
  67.          QS_IS_TRUE( m_pView->page()->totalBytes() > 100 );
  68.  
  69.          QS_END_TEST;
  70.          QS_TEST_COMPLETE;//Указываем, что тест завершен успешно
  71.      }
  72. };
  73.  
  74. #endif // QS_WEBKIT_H

Как видно из приведенного примера инициализацию и финализацию мы вынесли в отдельные слоты, вызываемые перед запуском и завершением каждого тестового слота. Тем самым мы концентрируемся уже непосредственно на написании самого теста. Т.е. часто повторяющиеся операции можно и нужно выносить в служебные слоты. Что позволяет вам создавать более лаконичные и понятные тесты. Какие именно слоты использовать решать вам. К примеру, если все тесты посвящены объекту m_pView, то стоит использовать слоты уровня инициализации и финализации класса. Все зависит от того, какую логику работы вы тестируете.

Вы уже наверное заметили, что для проверки различных ключевых условий реализован ряд проверочных макросов (ниже в справочном разделе приведен полный список всех проверочных макросов). В случае если проверяемое условие не будет выполнено – следовательно, тестовый слот будет прерван с указанием причины и точки возникновения проблемы, а управление будет передано следующему тестовому слоту. А сам тест будет признан проваленным. Например, рассмотрим строку (номер 27):

QS_IS_TRUE( connect( m_pView, 
SIGNAL( loadFinished( bool ) ), 
SLOT( slot_loadFinished( bool ) ) ) );

из слота:

void StartTestMethod( QString strTestMethodName )

в случае если метод connect вернет значение false, то проверочный макрос QS_IS_TRUE(...), прервет выполнение теста, так как мы ожидали получить true вместо false, т.е. возник сбой.

После завершения всех тестовых слотов, система выводит подробный отчет о результатах тестирования, в отчете помимо тестов, результатов, точек возникновения ошибок, еще так же указывается, сколько заняло по времени выполнение слота и самого тестового класса, что позволяет оценивать в будущем изменение скорости выполнения тестируемых узлов(особенно после рефакторинга):

Quick Unit version 1.0.0.1.qt473 rc installed
----------------------------------------------
| "Running the test class: " QS_WebKit
----------------------------------------------
test_LoadWebPage() "successfully completed" "Duration:" 00:00:16:652
----------------------------------------------
| "TEST CLASS RESULTS: " QS_WebKit
|----------------------------------------------
| "Test methods amount:" 3
| "Successfully passed:" 3
| "Not covered by reason of failure to test environment:" 0
| "Not covered by reason of the exception:" 0
| "Not covered by reason of a fatal error:" 0
| "Not run:" 0
|----------------------------------------------
| "Duration:" "00:00:22:156"
| ----------------------------------------------

НазадДалее
Категории раздела
QuickUnit [1]
Новости об изменениях в библиотеке QuickUnit
Архив записей
Наш опрос
Помогает ли проект QuickUnit Вам в решении ваших задач модульного тестирования
Всего ответов: 4
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0