Библиотека zsql_test_double_framework для эффективного создания unit-тестов логики взаимодействия с СУБД, начиная с версии 7.02
Стандартный инструмент ABAP Open SQL Test Double Framework, несомненно, является одним из самых мощных и удачных для тестирования логики взаимодействия с СУБД. К сожалению, данный фреймворк поддерживается только в новых версиях, начиная с 7.51. Для версий с 7.02 по 7.50 предлагается использовать аналог – библиотеку zsql_test_double_framework, которая обладает схожими возможностями и также позволяет писать unit-тесты для программ, работающих с СУБД.
Введение
Unit-тесты играют большую роль в процессе современной разработки ПО. Они позволяют проверять код на правильность очень быстро, зачастую за секунды. Это достигается изоляцией unit-тестов от любых внешних зависимостей, таких как сеть, файловая система или база данных.
Большинство ABAP-разработок используют СУБД, поэтому техника изоляции зависимости от базы данных является крайне важной для эффективного написания тестов.
ABAP SQL Test Double Framework, с моей точки зрения, – одна из лучших реализаций, о которой можно было только мечтать. Данный фреймворк позволяет создавать виртуальную базу данных со своими данными, никак не связанными с реальной СУБД. Программа продолжает работать как и раньше, с использованием инструкций Open SQL, но при этом работает с виртуальной СУБД, и мы можем использовать это в наших unit-тестах.
Пример работы с фреймворком можно посмотреть, например, здесь.
К сожалению, поддержка данного фреймворка начинается только с версии SAP BASIS 7.51, что недоступно для многих проектов. Например, на моём текущем проекте используется SAP ERP EHP 8, а также SAP Solution Manager, всё обновлено до самых «свежих» версий, но максимальная версия базиса у нас лишь 7.50. Поэтому тестировать базу данных с использованием данного инструмента мы на своём проекте не можем.
Проект zsql_test_double_framework
Для того чтобы получить возможности, схожие со стандартным фреймворком ABAP SQL Test Double Framework, но на версиях базиса 7.50 и ниже, я решил написать свою Z-разработку, которую я в итоге оформил как open source проект, и он доступен для использования всеми желающими.
Проект называется zsql_test_double_framework. Прочитать документацию и скачать проект для загрузки через ABAP Git можно по этой ссылке:
https://github.com/raaleksandr/zsql_test_double_framework
При создании проекта я преследовал следующие цели:
- Поддержка синтаксиса Open SQL.
- Сведение к минимуму необходимости адаптации имеющегося кода, написанного без учёта необходимости написания тестов.
- Поддержка основных конструкций, доступных в Open SQL для взаимодействия с ABAP-кодом – использование переменных как в условиях, так и для получения значений, поддержка for all entries, подзапросы и т.д.
Основное неудобство, которое придётся испытать при использовании библиотеки, заключается в необходимости переписывать текст SQL-запросов из статического в динамический вид, передав его через текстовую строку. Из-за того, что основная часть синтаксиса Open SQL поддерживается библиотекой, чаще всего будет достаточно обрамить имеющийся SQL-запрос в кавычки и сделать ряд несложных манипуляций.
В следующем разделе рассмотрим пример.
Пример написания тестов на отчёт
Предположим, что у нас есть отчёт, который выбирает данные из базы данных и выводит в ALV-грид.
Приведём код исходного отчёта до того, как мы напишем unit-тесты. SQL-запрос здесь написан в обычном виде через open sql.
TYPES: BEGIN OF ty_grid_line, carrname TYPE scarr-carrname, countryfr TYPE spfli-countryfr, cityfrom TYPE spfli-cityfrom, airpfrom TYPE spfli-airpfrom, countryto TYPE spfli-countryto, cityto TYPE spfli-cityto, airpto TYPE spfli-airpto, fldate TYPE sflight-fldate, price TYPE sflight-price, currency TYPE sflight-currency, paymentsum TYPE sflight-paymentsum, END OF ty_grid_line. TYPES ty_grid TYPE STANDARD TABLE OF ty_grid_line WITH KEY carrname. DATA: carrid TYPE scarr-carrid, fldate TYPE sflight-fldate. SELECT-OPTIONS: s_carrid FOR carrid, s_fldate FOR fldate. CLASS lcl_database_reader DEFINITION. PUBLIC SECTION. METHODS: read_data IMPORTING it_select_carrid TYPE typ_r_carrid it_select_fldate TYPE typ_r_fldate EXPORTING et_data TYPE ty_grid. ENDCLASS. CLASS lcl_application DEFINITION. PUBLIC SECTION. METHODS: start_of_selection. ENDCLASS. CLASS lcl_database_reader IMPLEMENTATION. METHOD read_data. SELECT scarr~carrname spfli~countryfr spfli~cityfrom spfli~airpfrom spfli~countryto spfli~cityto spfli~airpto sflight~fldate sflight~price sflight~currency sflight~paymentsum FROM sflight JOIN scarr ON scarr~carrid = sflight~carrid JOIN spfli ON spfli~carrid = sflight~carrid AND spfli~connid = sflight~connid INTO CORRESPONDING FIELDS OF TABLE et_data WHERE sflight~carrid IN it_select_carrid AND sflight~fldate IN it_select_fldate. ENDMETHOD. ENDCLASS. CLASS lcl_application IMPLEMENTATION. METHOD start_of_selection. DATA: lo_reader TYPE REF TO lcl_database_reader, lt_data_for_grid TYPE ty_grid, lo_alv TYPE REF TO cl_salv_table, lo_error TYPE REF TO cx_root, lv_error_text TYPE string. CREATE OBJECT lo_reader. lo_reader->read_data( EXPORTING it_select_carrid = s_carrid[] it_select_fldate = s_fldate[] IMPORTING et_data = lt_data_for_grid ). TRY. cl_salv_table=>factory( IMPORTING r_salv_table = lo_alv CHANGING t_table = lt_data_for_grid ). lo_alv->display( ). CATCH cx_root INTO lo_error. lv_error_text = lo_error->get_text( ). MESSAGE lv_error_text TYPE 'I' DISPLAY LIKE 'E'. ENDTRY. ENDMETHOD. ENDCLASS. START-OF-SELECTION. PERFORM start_of_selection. *&---------------------------------------------------------------------* *& Form START_OF_SELECTION *&---------------------------------------------------------------------* *& Entry point *&---------------------------------------------------------------------* *& --> p1 text *& <-- p2 text *&---------------------------------------------------------------------* FORM start_of_selection . DATA: lo_application TYPE REF TO lcl_application. CREATE OBJECT lo_application. lo_application->start_of_selection( ). ENDFORM.
Получившийся результат выводится в грид, как на рисунке 1.
Рис. 1. Результат отчёта в виде ALV-грида.
Перепишем отчёт, чтобы он работал через zsql_test_double_framework, а потом напишем на него unit-тест.
TYPES: BEGIN OF ty_grid_line, carrname TYPE scarr-carrname, countryfr TYPE spfli-countryfr, cityfrom TYPE spfli-cityfrom, airpfrom TYPE spfli-airpfrom, countryto TYPE spfli-countryto, cityto TYPE spfli-cityto, airpto TYPE spfli-airpto, fldate TYPE sflight-fldate, price TYPE sflight-price, currency TYPE sflight-currency, paymentsum TYPE sflight-paymentsum, END OF ty_grid_line. TYPES ty_grid TYPE STANDARD TABLE OF ty_grid_line WITH KEY carrname. DATA: carrid TYPE scarr-carrid, fldate TYPE sflight-fldate. SELECT-OPTIONS: s_carrid FOR carrid, s_fldate FOR fldate. CLASS lcl_database_reader DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING io_db_layer TYPE REF TO zif_zosql_db_layer OPTIONAL, read_data IMPORTING it_select_carrid TYPE typ_r_carrid OPTIONAL it_select_fldate TYPE typ_r_fldate OPTIONAL EXPORTING et_data TYPE ty_grid RAISING zcx_zosql_error. PRIVATE SECTION. DATA: go_db_layer TYPE REF TO zif_zosql_db_layer. ENDCLASS. CLASS lcl_application DEFINITION. PUBLIC SECTION. METHODS: start_of_selection. ENDCLASS. CLASS lcl_database_reader IMPLEMENTATION. METHOD constructor. IF io_db_layer IS BOUND. go_db_layer = io_db_layer. ELSE. go_db_layer = zcl_zosql_test_environment=>get_db_layer_for_production( ). ENDIF. ENDMETHOD. METHOD read_data. DATA: ls_param TYPE zosql_db_layer_param, lt_params TYPE zosql_db_layer_params, lv_select TYPE string. ls_param-param_name_in_select = ':it_select_carrid'. zcl_zosql_utils=>move_corresponding_table( EXPORTING it_table_src = it_select_carrid
Если хотите прочитать статью полностью и оставить свои комментарии присоединяйтесь к sapland
ЗарегистрироватьсяУ вас уже есть учетная запись?
Войти