Quick UnitАсинхронное модульное тестирование. В наше время разработчику уже крайне затруднительно обойти стороной асинхронное взаимодействие между блоками кода. Это и работа с web службами, работа с браузерными движками, и работа с потоками и т.д. и т.п. можно перечислять до бесконечности. И как следствие встает проблема организации модульного тестирования объектов, выполняющих операции асинхронно, а точнее сказать в инструменте, реализующем возможность создания асинхронных тестов.Прежде чем начнем, хочу уточнить, смысл термина «асинхронный тест». Под «асинхронным тестом», понимается такой тест, который мы можем завершить сами из любого потока в любой момент времени,из любой функции. Хочется еще указать на тот факт, что лично мне довелось увидеть только одну реализацию асинхронного тестирования и то, только для Silverlight 3.
Пример асинхронного теста на Silverlight
Конечно я не занимался масштабными поисками, но беглый осмотр показал, что ничего подобного, кроме как для Silvrlight к сожалению нет, ни для .net Framework нет, ни для native C++. А всякие хитрые решения с блокировками, запусками в фоновых потоках не в счет. Это только усложняет и затягивает процесс тестирования.
И так предлагаемый вашему вниманию инструмент называется QuickUnit, это наш внутренний продукт, о котором хочется рассказать и поделиться, не только бинарниками, но и исходниками. Он реализован пока только на языке C++ при помощи библиотеки QT. Почему QT, да потому что её реализация системы метаданных, как нельзя лучше подходит для решения задачи асинхронного тестирования (она мне очень напоминает рефлексию в .net). В будущем планируется реализация для платформ .net и mono.
Представим себе, что нам необходимо написать модульный тест для класса, выполняющего операции в фоновом потоке. Для примера напишем маленький тест для метода QWebView::load( ... );, так как результат выполнения данной функции мы получим только через обработку сигнала loadFinished( bool ), Для сравнения сначала напишем "асинхронный" тест с помощью CPPUNIT, а затем с помощью QuickUnit и сравним полученный результат. И так перед нами тестовый класс, реализованный с помощью CPPUNIT:
Пример тестирования асинхронного метода с помощью CPPUNIT
Главная проблема, это удержать исполняющий поток в тестовой функции, до того момента пока не будет полностью обработан сигнал loadFinished( bool ) в слоте slot_load_finished( bool bOk ) , и только затем поток можно будет пускать далее. Если не удерживать поток, то по сути тест нельзя считать правильным, так как он с большой долей вероятности завершится преждевременно. Самый простой вариант удержания исполняющего потока, это принудительная обработка сообщений в очереди:
однако этот способ трудоемок для процессора, конечно это не смертельно, но не дает понять на этапе тестирования и разработки, как реализуемый вами код в действительности нагружает процессор. Теперь рассмотрим предлагаемое нами решение для таких случаев: Пример асинхронного модульного тестирования
Как видно из примера декларативная часть тестового класса минимальна. Проблема удержания исчезла, код стал компактнее и проще. Правда возникает другая, если разработчик забудет указать, что тест надо завершать, система будет ждать вечно (в планы у нас входит timeout для таких случаев, что бы не тормозить процесс тестирования в целом) команды на завершение. И конечно главное отличие от CPPUNIT и других решений это привязка к QT, т.е. перед использованием QuickUnit необходимо сначала установить QT. Хотя на наш взгляд это не так уж и много, для упрощения тестирования асинхронных операций. Процесс установки описан в руководстве разработчика. Кратко рассмотрим основные возможности QuickUnit. Сам тестовый класс должен быть наследником QS_TestClass и быть так же классом QT ( объявляется макрос Q_OBJECT ). Для отделения тестовых слотов от посторонних, первые имеют приставку test_. Все тестовые слоты выполняются в контексте основного потока, что позволяет использовать GUI классы, COM объекты, одним словом все те классы, которые могут быть созданы только в контексте основного потока приложения. Тестовые слоты делятся на две категории критические и не критические. Критический тестовый слот – является ключевым для всего тестового класса, если он не прошел проверку, то дальнейшие тестовые слоты выполняться не будут, управление будут передано следующему тестовому классу. Для указания системе факта завершения теста, используется макрос QS_TEST_COMPLETE;. Благодаря такому подходу можно без труда реализовать тестирование любого асинхронного алгоритма. Тестовые слоты имеют набор атрибутов. Задача атрибута – указать системе, что слот должен выполняться с некоторыми особенностями. Для минимизации на декларирование, атрибуты включаются в наименование самого тестового слота, к примеру:
Пример использования атрибутов
В текущей версии реализовано пока только два атрибута _Fatal и _Repeat_N. Первый указывает, что слот является критическим, а второй указывает, что слот надо повторно взывать N раз подряд. По умолчанию тестовый слот не критичен и выполняется только один раз. Макросы QS_BEGIN_TEST и QS_END_TEST это блок try catch в случае перехвата исключения тестовый слот будет прерван, и зафиксирован, как не прошедший проверку. Так же имеется группа проверочных макросов с ними можно ознакомиться в руководстве разработчика. После описания тестового класса его остается только зарегистрировать. Регистрацию рекомендуется реализовывать в main.cpp Quick Unit подходит не только для тестирования под QT, но так же полностью совместим с WIN32, ATL, MFC.По результатам тестирования в консоль выводится отчет о пройденных тестах, с указанием причин и точек возникновения ошибок, в отчет так же включено время выполнения тестового слота, класса. Мы искренне надеемся, что QuickUnit поможет в решении ваших задач. Все предложения и замечания можно и нужно оставлять здесь. |
|
||||||||||||||
Copyright Quick Soft © 2011 Бесплатный конструктор сайтов - uCoz |