Методология тестирования, управляемого данными (DDT) применяется в автоматизации тестирования ПО, представляет собой тестирование, выполнение и верификация которого производится на основе данных, которые хранятся в БД или любых других источниках данных.
Обычно сравнивают эталонные данные с теми, что на выходе получает система из метода (функции, программы и т.п.).
Тестирование, управляемое данными подразумевает разделение юнит тестов и данных, которые в них проверяются. Юнит тесты получают эталонные данные из некого источника и сравнивают их с результатами, полученными при тестировании объекта.
Изначально ABAP Unit не предоставляет никакого сервиса для хранения и ведения тестируемых данных, как например это делают другие фреймворки для тестирования: jUnit, nUnit. В статье пойдет речь о том как обойти это недоразумение.
В качестве подобного сервиса можно использовать контейнеры данных eCATT. Что такое eCATT и для чего он нужен можно посмотреть тут. Нас интересует один из элементов eCATT, а именно контейнер тестовых данных. Исходя из названия, становится понятно, что контейнер позволяет хранить внутри себя какие-то данные, но кроме хранения можно так же и вести (изменять) эти данные.
Рассмотрим небольшой пример, допустим, есть метод рассчитывающий тип треугольника относительно размеров его сторон, как известно из школьной программы, тип может быть следующим:
- Равносторонний (все стороны равны)
- Равнобедренный (хотя бы две стороны равны)
- Разносторонний (нет равных сторон).
Создадим класс ZCL_TRIANGLE c указанными атрибутами:
Метод GET_TYPE:
Параметры метода:
Реализация:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | method GET_TYPE.   IF ( iv_a <= 0 ) OR ( iv_b <= 0 ) OR ( iv_c <= 0 ).     RAISE EXCEPTION TYPE zcx_wrong_tria_parameters.   ENDIF.   IF ( iv_a = iv_b AND iv_b = iv_c ).     re_type = zcl_triangle=>cv_equilateral. " Односторонний     RETURN.   ENDIF.   IF ( iv_a = iv_b ) OR ( iv_b = iv_c ) OR ( iv_c = iv_a ).     re_type = zcl_triangle=>cv_isosceles. " равнобедренный     RETURN.   ENDIF.   re_type = zcl_triangle=>cv_scalene. " разносторонний endmethod. | 
Как видно из примера, в случае некорректных данных вызывается исключение. В данной статье не описывается создание и использование классов исключений, при желании можете посмотреть в ранее опубликованной статье.
Статья подразумевает что вы знаете как писать юнит тесты, а если нет, добро пожаловать в введение.
Напишем сначала юнит тест, проверяющий метод без использования каталогов тестов:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | *"* use this source file for your ABAP unit test classes CLASS lcl_triangle_test DEFINITION FOR TESTING RISK LEVEL HARMLESS.   PUBLIC SECTION.     METHODS:       test_scalene FOR TESTING,       test_isosceles FOR TESTING,       test_equilateral FOR TESTING. ENDCLASS. CLASS lcl_triangle_test IMPLEMENTATION.   METHOD test_equilateral.     DATA:       lv_type TYPE i,       lo_exc  TYPE REF TO zcx_wrong_tria_parameters.     " Равносторонний     TRY.       cl_abap_unit_assert=>assert_equals(         act = zcl_triangle=>get_type(  iv_a = 1                                        iv_b = 1                                        iv_c = 1 )         exp = zcl_triangle=>cv_equilateral       ).     CATCH zcx_wrong_tria_parameters INTO lo_exc.       cl_abap_unit_assert=>fail(         EXPORTING           msg    = lo_exc->get_text( )       ).     ENDTRY.   ENDMETHOD.   METHOD test_isosceles.     DATA:       lv_type TYPE i,       lo_exc  TYPE REF TO zcx_wrong_tria_parameters.     " Равнобедренный     TRY.       cl_abap_unit_assert=>assert_equals(         act = zcl_triangle=>get_type(  iv_a = 1                                        iv_b = 1                                        iv_c = 3 )         exp = zcl_triangle=>cv_isosceles       ).     CATCH zcx_wrong_tria_parameters INTO lo_exc.       cl_abap_unit_assert=>fail(         EXPORTING           msg    = lo_exc->get_text( )       ).     ENDTRY.   ENDMETHOD.   METHOD test_scalene.     DATA:       lv_type TYPE i,       lo_exc  TYPE REF TO zcx_wrong_tria_parameters.     " Разносторонний     TRY.       cl_abap_unit_assert=>assert_equals(         act = zcl_triangle=>get_type(  iv_a = 1                                        iv_b = 2                                        iv_c = 3 )         exp = zcl_triangle=>cv_scalene       ).     CATCH zcx_wrong_tria_parameters INTO lo_exc.       cl_abap_unit_assert=>fail(         EXPORTING           msg    = lo_exc->get_text( )       ).     ENDTRY.   ENDMETHOD. ENDCLASS. | 
Как вы можете убедиться, запустив тест (ctrl+shift+F10), он будет успешно пройден:
Но что делать, если количество тестовых данных возрастает? Описывать множество возможных вариантов для тестирования в самом юнит тесте не корректно, т.к. объем кода в этом случае будет огромным. Тут к нам на помощь приходит методология тестирования, управляемого данными и каталог тестовых данных eCATT.
- Создаем каталог, запустив транзакцию SECATT:
- Определяем параметры (то из чего состоит) каталога:
- Далее необходимо определить сами данные, данные определяются в так называемых вариантах, по умолчанию всегда в системе есть вариант ECATTDEFAULT, его будем игнорировать в дальнейшем:
На данном этапе закончим с eCATT и создадим один небольшой класс, от которого будут наследоваться наши тестовые классы, в нем мы напишем метод, запускающий тестовые методы с указанным каталогом тестов.
Атрибуты:
У класса будет единственный метод run_variants, который используя API eCATT, будет получать тестовые данные, API реализовано в классе cl_apl_ecatt_tdc_api. Более подробное описание API можно найти официальной документации.
Параметры метода:
Код:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | METHOD run_variants.   DATA: lt_variants TYPE etvar_name_tabtype,         lo_ex TYPE REF TO cx_root.   " Получаем данные SECATT   TRY .       go_tdc_api = cl_apl_ecatt_tdc_api=>get_instance( iv_container_name ).       " Считываем все варианты из контейнера       lt_variants = go_tdc_api->get_variant_list( ).     CATCH cx_ecatt_tdc_access INTO lo_ex.       cl_aunit_assert=>fail(           msg  = |Варианты { gv_current_variant } не считаны: { lo_ex->get_text( ) }|           quit = if_aunit_constants=>no ).       RETURN.   ENDTRY.   " Удаляем вариант по умолчанию   DELETE lt_variants WHERE table_line = 'ECATTDEFAULT'.   " Запускаем тестовый метод со всеми тестовыми данными (вариантами)   " Метод не должен содержать параметров и должен быть создан в дочерних классах   LOOP AT lt_variants INTO gv_current_variant.     TRY .         CALL METHOD (iv_method_name).       CATCH cx_root INTO lo_ex.         cl_aunit_assert=>fail(             msg  = |Вариант { gv_current_variant } не выполнен: { lo_ex->get_text( ) }|             quit = if_aunit_constants=>no ).     ENDTRY.   ENDLOOP. ENDMETHOD. | 
Далее перепишем наш тестовый класс:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | *"* use this source file for your ABAP unit test classes DEFINE get_val.   try.       go_tdc_api->get_value(               exporting                 i_param_name = &1                 i_variant_name = gv_current_variant               changing                 e_param_value = &2 ).     catch cx_root.   endtry. END-OF-DEFINITION. CLASS lcl_triangle_test DEFINITION FOR TESTING RISK LEVEL HARMLESS INHERITING FROM zcl_ecat_unit.   PUBLIC SECTION.     METHODS:       test_type FOR TESTING,       test_type_variant. ENDCLASS. CLASS lcl_triangle_test IMPLEMENTATION.   METHOD test_type.     run_variants(         iv_container_name = 'ZTRIANGLE_CATALOG'         iv_method_name  = 'TEST_TYPE_VARIANT' ).   ENDMETHOD.   METHOD test_type_variant.     DATA: lv_a TYPE i,           lv_b TYPE i,           lv_c TYPE i,           lv_exp_type TYPE i,           lo_exc TYPE REF TO zcx_wrong_tria_parameters.     get_val: 'A' lv_a,              'B' lv_b,              'C' lv_c,              'EXP_TYPE' lv_exp_type.     TRY.         cl_abap_unit_assert=>assert_equals(           exp = lv_exp_type           act = zcl_triangle=>get_type( iv_a = lv_a                                         iv_b = lv_b                                         iv_c = lv_c )           quit = if_aunit_constants=>no           msg = |Не верное значение типа для варианта { gv_current_variant }| ).       CATCH zcx_wrong_tria_parameters INTO lo_exc.         cl_abap_unit_assert=>fail(           EXPORTING             msg    = |Ошибка при передаче тестовых параметров { gv_current_variant }|             quit   = if_aunit_constants=>no         ).     ENDTRY.   ENDMETHOD. ENDCLASS. | 
Как видно покрытие тестами возрасло, а код уменьшился на порядок. В итоге благодаря DDT и eCATT можно сильно облегчить себе жизнь в ходе тестирования, опираясь на данные, не зашитые в самом юнит тесте.
Материал данной статьи был позаимствован из следующего источника:









