+7 (495) 229-0436   shopadmin@itshop.ru 119334, г. Москва, ул. Бардина, д. 4, корп. 3
 
 
Вход
 
 
Каталог
 
 
Подписка на новости
Новости ITShop
Windows 7 и Office: Новости и советы
Обучение и сертификация Microsoft
Вопросы и ответы по MSSQLServer
Delphi - проблемы и решения
Adobe Photoshop: алхимия дизайна
 
Ваш отзыв
Оцените качество магазина ITShop.ru на Яндекс.Маркете. Если вам нравится наш магазин - скажите об этом Google!
 
 
Способы оплаты
 
Курс расчета
 
 1 у.е. = 94.09 руб.
 
 Цены показывать:
 
 
 
 
  
Новости, статьи, акции
 

Асинхронное модульное тестирование для С++

09.11.2011 16:30

В наше время разработчику уже крайне затруднительно обойти стороной асинхронное взаимодействие между блоками кода. Это и работа с web службами, работа с браузерными движками, и работа с потоками и т.д. и т.п. можно перечислять до бесконечности. И как следствие встает проблема организации модульного тестирования объектов, выполняющих операции асинхронно, а точнее сказать в инструменте, реализующем возможность создания асинхронных тестов.Прежде чем начнем, хочу уточнить, смысл термина "асинхронный тест". Под "асинхронным тестом", понимается такой тест, который мы можем завершить сами из любого потока в любой момент времени, из любой функции.

 В качестве вступления хочется заметить, что лично мне довелось увидеть только одну реализацию библиотеки асинхронного тестирования и то, только для Silverlight 3 и 4 (из пакета Silverlight Toolkit).

    [TestClass]
    public class MyTest_test : SilverlightTest
    {
        [TestMethod]
        [Asynchronous]//указываем что тест асинхронный
        public void test_AsyncExample()
        {
            //в фоновом потоке выполняем длительную операцию
            Thread cThread =
                new Thread( delegate()
                                {
                                    //какая-то длительная опреация
 
                                    //указываем что тест пройден!
                                    <b>EnqueueTestComplete();</b>
                                } );
            cThread.Start();
        }
    }

 Конечно я не занимался масштабными поисками, но беглый осмотр показал, что ничего подобного, кроме как для Silvrlight к сожалению нет, ни для .net Framework нет, ни для native C++. А всякие хитрые решения с блокировками, запусками в фоновых потоках не в счет. Это только усложняет и затягивает процесс тестирования.

 И так предлагаемый вашему вниманию инструмент называется QuickUnit, это открытая библиотека, написанная на С++ с использованием QT 4.7 распространяется под лицензией LGPL 2.1. Почему реализована на QT, да потому что её реализация системы метаданных, как нельзя лучше подходит для решения задачи асинхронного тестирования (она мне очень напоминает рефлексию в .net). В будущем планируется реализация для платформ .net и mono.

 Прежде чем приступим к рассмотрению самой библиотеки, давайте рассмотрим небольшой пример: представим себе, что нам необходимо написать модульный тест для класса, выполняющего операции в фоновом потоке. Для примера напишем маленький тест для метода QWebView::load(… );, так как результат выполнения данной функции мы получим только через обработку сигнала loadFinished( bool ), Для сравнения сначала напишем "асинхронный" тест с помощью CPPUNIT, а затем с помощью QuickUnit и сравним результат.

Рассмотрим тестовый класс, реализованный с помощью CPPUNIT:

#ifndef CWEBVIEWTEST_H
#define CWEBVIEWTEST_H
 
class CWebViewTest : public QObject,
                     public CPPUNIT_NS::TestFixture
{
    Q_OBJECT
 
public:
 
    CWebViewTest( QObject *parent = 0 );
    ~CWebViewTest();
 
    CPPUNIT_TEST_SUITE( CWebViewTest );
        CPPUNIT_TEST( test_WebView_Load );
    CPPUNIT_TEST_SUITE_END();
 
public:
 
    //подготовка теста
    virtual void setUp()
    {
        m_bPassed = false;
        m_pView = new QWebView( 0 );
    };
 
    //наводим порядок после прохождения теста
    virtual void tearDown()
    {
        delete m_pView;
    };
 
private:
 
    //тестируемый объект
    QWebView * m_pView;
 
    //уведомление о завершении теста
    bool m_bPassed;
       
private:
 
    //тест асинхронного метода
    void test_WebView_Load()
    {
        connect( m_pView,
                 SIGNAL( loadFinished( bool ) ),
                 SLOT( slot_load_finished( bool ) ) );
 
        m_pView->load( QUrl("http://www.google.ru") );
 
        /* здесь встает проблема преждевременного завершения теста,
            необходимо удержать исполняющий поток
            до момента получения сигнала loadFinished( bool )
        */
 
        //один из вариантов удержания (однако излишняя нагрузка на ЦП)
        while ( !m_bPassed )
        {
            QApplication::processEvents( QEventLoop::ExcludeUserInputEvents );
        }
       
    }
 
private slots:
 
    void slot_load_finished( bool bOk )
    {
        CPPUNIT_ASSERT(bOk);
        CPPUNIT_ASSERT( m_pView->page()->totalBytes() > 100 );
 
        m_bPassed = true;//сообщаем о завершении
    }
   
};
 
#endif // CWEBVIEWTEST_H

 Главная проблема - это удержать исполняющий поток в тестовой функции, до того момента пока не будет полностью обработан сигнал loadFinished( bool ) в слоте slot_load_finished( bool bOk ), и только затем поток можно будет пускать далее. Если не удерживать поток, то по сути тест нельзя считать правильным, так как он с большой долей вероятности завершится преждевременно. Самый простой вариант удержания исполняющего потока, это принудительная обработка сообщений в очереди:

//один из вариантов удержания (однако излишняя нагрузка на ЦП)
while ( !m_bPassed )
{
    QApplication::processEvents( QEventLoop::ExcludeUserInputEvents );
}

 однако этот способ трудоемок для процессора, конечно это не смертельно, но не дает понять на этапе тестирования и разработки, как реализуемый вами код в действительности нагружает процессор.

Теперь рассмотрим туже задачу, но с использованием QuickUnit:

#ifndef ASYNCHRONOUS_TEST_EXAMPLE_H
#define ASYNCHRONOUS_TEST_EXAMPLE_H
 
#include <QS_QuickUnit.h>
#include <QtWebKit\QtWebKit>
 
class AsynchronousTestExample : public QS_TestClass
{
    Q_OBJECT
 
private:

    QWebView * m_pView;
 
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://custom.site.com" ) );
 
        QS_END_TEST;
    }//по выходу из функции тест не завершается, поток держать уже не надо!

    //посторонний слот (система его вызывать не будет,
    //так как он не имеет приставки 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 //ASYNCHRONOUS_TEST_EXAMPLE_H

 Как видно из примера декларативная часть тестового класса минимальна. Проблема удержания исчезла, код стал компактнее и понятнее. Но как это всегда бывает за удобства надо платить:
 Если разработчик забудет указать, что тест надо завершать, система будет ждать вечно (в планы у нас входит timeout для таких случаев, что бы не тормозить процесс тестирования в целом) команды на завершение;
Данная библиотека реализована на QT, т.е. перед использованием QuickUnit необходимо сначала установить QT, и если вы используете Visual Studio то и аддон для студии.

Подведем итоги:

 Что мы приобретаем если используем QuickUnit:

  • Нет нужды ломать голову, как удержать поток в тестовой функции;
  • Минимальная декларативная часть тестового класса;
  • Гибкость при построении тестов, для комплексного тестирования много поточных блоков кода;
  • Малый размер библиотеки;
  • Кросс-платформенность.

 Недостатки:

  • Привязка к QT;
  • Внимательно писать тесты, не забывать о завершении.

Кратко рассмотрим основные требования и возможности QuickUnit.

 Сам тестовый класс должен быть наследником QS_TestClass и классом QT ( объявляется макрос Q_OBJECT ). Для отделения тестовых слотов от посторонних, первые имеют приставку test_. Все тестовые слоты выполняются в контексте основного потока, что позволяет использовать GUI классы, COM объекты, одним словом все те классы, которые могут быть созданы только в контексте основного потока приложения.

 Тестовые слоты делятся на две категории критические и не критические. Критический тестовый слот - является ключевым для всего тестового класса, если он не прошел проверку, то дальнейшие тестовые слоты выполняться не будут, управление будут передано следующему тестовому классу. Для указания системе факта завершения теста, используется макрос QS_TEST_COMPLETE;. Благодаря такому подходу можно без труда реализовать тестирование любого асинхронного алгоритма.

 Тестовые слоты имеют набор атрибутов. Задача атрибута - указать системе, что слот должен выполняться с некоторыми особенностями. Для минимизации на декларирование, атрибуты включаются в наименование самого тестового слота, к примеру:

#ifndef ATTRIBUTE_USAGE_EXAMPLE_H
#define ATTRIBUTE_USAGE_EXAMPLE_H
 
#include <QS_QuickUnit.h>
 
class AttributeUsageExample : public QS_TestClass
{
    Q_OBJECT
 
        private slots:
 
            void test_myTest_Fatal()
            {
                QS_BEGIN_TEST;
 
                //реализуем логику тестирования
 
                QS_END_TEST;
                QS_TEST_COMPLETE;
            }
 
            void test_myTest_Repeat_15()
            {
                QS_BEGIN_TEST;
 
                //реализуем логику тестирования
 
                QS_END_TEST;
                QS_TEST_COMPLETE;
            }
 
            void test_myTest_Fatal_Repeat_15()
            {
                QS_BEGIN_TEST;
 
                //реализуем логику тестирования
 
                QS_END_TEST;
                QS_TEST_COMPLETE;
            }
};
 
#endif //ATTRIBUTE_USAGE_EXAMPLE_H

 В текущей версии реализовано пока только два атрибута _Fatal и _Repeat_N. Первый указывает, что слот является критическим, а второй указывает, что слот надо повторно взывать N раз подряд. По умолчанию тестовый слот не критичен и выполняется только один раз. Макросы QS_BEGIN_TEST и QS_END_TEST это блок try catch в случае перехвата исключения тестовый слот будет прерван, и зафиксирован, как не прошедший проверку. Так же имеется группа проверочных макросов с ними можно ознакомиться в руководстве разработчика. После описания тестового класса его остается только зарегистрировать. Регистрацию рекомендуется реализовывать в main.cpp

 Quick Unit подходит не только для тестирования под QT, но так же полностью совместим с WIN32, ATL, MFC. По результатам тестирования в консоль выводится отчет о пройденных тестах, с указанием причин и точек возникновения ошибок, в отчет так же включено время выполнения тестового слота, класса.

 Мы искренне надеемся, что QuickUnit поможет в решении ваших задач. Все предложения и замечания можно и нужно оставлять здесь.

Ссылки по теме

  
Помощь
Задать вопрос
 программы
 обучение
 экзамены
 компьютеры
Бесплатный звонок
ICQ-консультанты
Skype-консультанты

Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 
Бестселлеры
Курсы обучения "Atlassian JIRA - система управления проектами и задачами на предприятии"
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2019. Все языки. Электронный ключ
Курс "Oracle. Программирование на SQL и PL/SQL"
Курс "Основы TOGAF® 9"
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Курс "Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации"
 

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

В нашем магазине вы можете приобрести лицензионное ПО выбрав необходимое из широкого спектра и ассортимента по самым доступным ценам. Наши менеджеры любезно помогут определиться с выбором ПО, которое необходимо именно вам. Также мы проводим учебные курсы. Мы приглашаем к сотрудничеству учебные центры, организаторов семинаров и бизнес-тренингов, преподавателей. Сфера сотрудничества - продвижение бизнес-тренингов и курсов обучения по информационным технологиям.



 

О нас

 
Главная
Каталог
Новинки
Акции
Вакансии
 

Помощь

 
Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 

Способы оплаты

 

Проекты Interface Ltd.

 
Interface.ru   ITShop.ru   Interface.ru/training   Olap.ru   ITnews.ru  
 

119334, г. Москва, ул. Бардина, д. 4, корп. 3
+7 (495) 229-0436   shopadmin@itshop.ru
Проверить аттестат
© ООО "Interface Ltd."
Продаем программное обеспечение с 1990 года