Все тестовые методы должны быть слотами, а и их наименование должно начинаться с префикса test_, так как движку модульного тестирования нужно отделять обычные слоты, от тестовых слотов. Под обычными слотами понимаются слоты, используемые для обработки сигналов сторонних объектов, участвующих в тестировании. Так же для сокращения декларативной части тестового класса, нами было принято решение о внесении параметров — атрибутов тестовых слотов непосредственно в их наименование (аналогично использованию префикса test_ ). Что позволит быстро менять параметры тестового метода. Например:
- #ifndef MYTEST_H
- #define MYTEST_H
- #include <QS_QuickUnit.h>
- class MyTest : public QS_TestClass
- {
- Q_OBJECT
- private slots:
- void test_myTest_Fatal_Repiat_15()
- {
- QS_BEGIN_TEST;
- //реализуем логику тестирования
- QS_END_TEST;
- QS_TEST_COMPLETE;
- }
- };
- #endif //MYTEST_H
элементы _Fatal и _Repiat_15 в наименовании тестового слота , являются атрибутами. Задача атрибута — указать системе, что слот должен выполняться с некоторыми особенностями. К примеру, указать системе, что слот надо выполнить повторно n - раз. В текущей версии реализовано пока только два атрибута. Далее список будет расширен.
Поскольку все тесты являются асинхронными, то за момент завершения теста отвечает уже разработчик. Что бы указать системе, что тест завершен - необходимо использовать макрос QS_TEST_COMPLETE. Его задача указать системе что, тест пройден успешно и можно переходить к следующему. В случае если вы забудете указать системе факт завершения, то тест никогда не завершиться (в будущей версии планируется timeout для таких ситуаций). Так же, для обработки возникающих исключений, реализовано два макроса QS_BEGIN_TEST и QS_END_TEST. Они представляют собой не что иное, как блок try catch. В блоке catch происходит завершение теста с указанием, что он завершен аварийно.
Рассмотрим чуть более сложный пример, раскрывающий, что же такое асинхронное тестирование на практике. Мы напишем тест, который будет тестировать загрузку веб странички с помощью QWebView.
- #ifndef QS_WEBKIT_TEST_H
- #define QS_WEBKIT_TEST_H
- #include <QS_QuickUnit.h>
- #include <QtWebKit>
- class QS_WebKit : public QS_TestClass
- {
- Q_OBJECT
- private slots:
- void test_LoadWebPage()
- {
- QS_BEGIN_TEST;
- m_pView = new QWebView( 0 );
- connect( m_pView,
- SIGNAL( loadFinished( bool ) ),
- SLOT( slot_loadFinished( bool ) ) );
- m_pView->load( QUrl( "http://www.google.ru" ) );
- QS_END_TEST;
- }//по выходу из функции тест не завершается!
- void slot_loadFinished ( bool ok )
- {
- QS_BEGIN_TEST;
- //проверяем результат
- QS_IS_TRUE( ok );
- QS_IS_TRUE( m_pView->page()->totalBytes() > 100 );
- QS_END_TEST;
- QS_TEST_COMPLETE;//Указываем, что тест завершен успешно
- }
- };
- #endif //QS_WEBKIT_TEST_H
Как видно из примера, теперь можно тестировать любые асинхронные операции. Особо хочу обратить внимание, что все тестовые слоты выполняются в контексте основного потока приложения, что позволяет свободно использовать виджеты, COM объекты и прочие объекты которые могут быть созданы только в контексте основного потока. Система полностью совместима с MFC, ATL и Win32, что позволяет вам использовать ее не только для QT.
Для оптимизации тестирующего кода, введены еще дополнительно 4 системных слота, все эти слоты являются критическими (по умолчанию имеют атрибут _Fatal):
|
вызывается перед запуском тестового класса, используется для инициализации объектов класса, вызывается один раз в рамках своего класса; |
|
вызывается по прохождении всех тестовых слотов, и используется для освобождения всех ресурсов занятых слотом void StartTestClass(); |
|
вызывается системой перед запуском каждого тестового слота, используется для инициализации необходимых объектов для конкретного тестового случая; |
|
вызывается системой по завершении каждого тестового слота, используется для освобождения занятых ресурсов; |
Рассмотрим пример использования некоторых из них.
- #ifndef QS_WEBKIT_H
- #define QS_WEBKIT_H
- #include <QS_QuickUnit.h>
- #include <QtWebKit>
- #include <QUrl>
- class QS_WebKit : public QS_TestClass
- {
- Q_OBJECT
- private:
- QWebView * m_pView;
- protected slots:
- /* Перед запуском тестового слота, создаем объект,
- * соединяем сигналы и слоты
- */
- void StartTestMethod( QString strTestMethodName )
- {
- QS_BEGIN_TEST;
- m_pView = new QWebView( 0 );
- QS_IS_TRUE( connect( m_pView,
- SIGNAL( loadFinished( bool ) ),
- SLOT( slot_loadFinished( bool ) ) ) );
- QS_END_TEST;
- QS_TEST_COMPLETE;
- }
- /* после завершения тестового слота удаляем объект
- */
- void CompleteTestMethod( QString strTestMethodName, QS_TestResult eResult )
- {
- QS_BEGIN_TEST
- delete m_pView;
- m_pView = 0;
- QS_END_TEST;
- QS_TEST_COMPLETE;
- }
- private slots:
- //теперь объем стал меньше, и можно сфокусироваться на тестировании
- void test_LoadWebPage()
- {
- QS_BEGIN_TEST;
- m_pView->load( QUrl( "http://www.google.ru" ) );
- QS_END_TEST;
- }
- //сигнал от браузера
- void slot_loadFinished ( bool ok )
- {
- QS_BEGIN_TEST;
- //проверяем результат
- QS_IS_TRUE( ok );
- QS_IS_TRUE( m_pView->page()->totalBytes() > 100 );
- QS_END_TEST;
- QS_TEST_COMPLETE;//Указываем, что тест завершен успешно
- }
- };
- #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"
| ----------------------------------------------
Назад | Далее |