Привет Всем !
Хотел бы поделится инструментом для юнит тестирования, который разработали я и мои коллеги для внутреннего использования. Инструмент предназначен для упрощения загрузки данных для юнит тестов. Мы сейчас ведем большой проект и приходится готовить большое количество табличных данных, например, выборки из BKPF/BSEG/BSET. Проверяемый код тоже обычно возвращает сложные структуры или таблицы (которые надо сверить с ожидаемыми).
Загрузчик данныхХардкод подобных данных прямо в юнит тесте - не вариант - слишком много кодить, сложно поддерживать и расширять тесты, ужасная читабельность. Поэтому мы решили разработать инструмент, который бы загружал данные из текстовых файлов с TAB разделителем. Они, в свою очередь, готовились бы удобным образом в Excel. К инструменту предъявлялись такие требования:
- все тесты должны собираться в один (zip?) файл
- ... и загружаться в систему, в частности быть частью пакета разработки для переноса на клиентские системы (бинарные объекты W3MI?)
- процедура загрузки должна автоматически определять структуру файлов и проверять ее совместимость с целевой переменной (структурой или таблицей)
- она должна уметь пропускать поля, которых нет в текстовом файле (
нестрогий режим) в случае, если полей в целевой структуре слишком много и они не относятся к тесту (как например FI таблицы - зачем готовить "сотню" полей если для теста надо десяток)
Код тест класса в таком случае выглядит так:
Code:
...
call method o_ml->load_data " Загрузить тестовые данные (структура)
exporting i_obj = 'TEST1/bkpf'
importing e_container = ls_bkpf.
call method o_ml->load_data " Загрузить тестовые данные (таблица)
exporting i_obj = 'TEST1/bseg'
i_strict = abap_false
importing e_container = lt_bseg.
...
call method o_test_object->some_processing " Вызов тестируемого кода
exporting i_bkpf = ls_bkpf
it_bseg = lt_bseg
importing e_result = l_result.
assert_equals(...).
...
Первая часть кода берет TAB delimited файл bseg.txt из каталога TEST1, ZIP архива, загруженного как бинарный объект через SMW0 ...
Code:
BUKRS BELNR GJAHR BUZEI BSCHL KOART ...
1000 10 2015 1 40 S ...
1000 10 2015 2 50 S ...
... и кладет данные во внутренню таблицу с типом строки BSEG (выполняя по ходу всякие ALPHA преобразования и т.п.)
Хранилище данныхПозже появилось еще одно требование: некоторый код достаточно сложно тестировать, если посередине его выполняется select. Конечно, правильный дизайн кода подразумевает разделение выборок из БД и логики, но это не всегда возможно (ну или как минимум довольно сложно). Таким образом нам нужен был простой вызов, который можно было бы использовать вместо select для тестового окружения. Мы назвали эту возможность Store (кстати очень хорошо ложится на ново-анонсированную фичу TEST-SEAM из ABAP 7.50 - когда только она появится в живых системах ...)
Тестовый класс, в таком случае, загружает данные и сохраняет их в Хранилище с определенным ярлыком:
Code:
...
call method o_ml->store " Сохранить данные с ярлыком 'BKPF'
exporting i_name = 'BKPF'
i_data = ls_bkpf. " структура
...
... а боевой код может извлечь данные вместо выборки из БД:
Code:
...
if some_test_env_indicator = abap_false. " Продуктив
" Тут выборки из БД
else. " Тестовое окружение
call method zcl_mockup_loader=>retrieve
exporting i_name = 'BKPF'
importing e_data = me->fi_doc_header
exceptions others = 4.
endif.
if sy-subrc is not initial.
" Данные не выбраны - обработка ошибок
endif.
...
Также в случае большого количества тестов удобно было бы загрузить сразу таблицу с подготовленными данными и фильтровать их по каким-то ключевым полям, значения которых доступны в боевом коде. Такую возможность тоже реализовали:
Тестовый класс:
Code:
...
call method o_ml->store " Сохранить данные с ярлыком 'BKPF'
exporting i_name = 'BKPF'
i_tabkey = 'BELNR' " Определить ключевое поле для таблицы
i_data = lt_bkpf. " Таблица с множеством записей
...
Боевой код:
Code:
...
if some_test_env_indicator = abap_false. " Продуктив
" Тут выборки из БД
else. " Тестовое окружение
call method zcl_mockup_loader=>retrieve
exporting i_name = 'BKPF'
i_sift = l_document_number " Отфильтровать данные по значению некой локальной переменной
importing e_data = me->fi_doc_header " одна запись таблицы !
exceptions others = 4.
endif.
if sy-subrc is not initial.
" Данные не выбраны - обработка ошибок
endif.
...
В результате у нас появляется удобная возможность делать полностью динамические тесты, покрывающие большинство кода, в том числе кода с выборками из БД. Конечно, одного данного инструмента для этого недостаточно - требуется правильный дизайн "боевого" кода, разделение бизнес логики и выборок из БД. Но с ZMOCKUP_LOADER и "хранилищем" это происходит гораздо удобнее.

Код проекта доступен на нашей странице на github:
http://sbcgua.github.io/mockup_loader/Надеюсь кому-то окажеться полезным ! =)
С уважением, Александр