Надев защитный шлем, продолжаем разговор без предисловий.
Грабля вторая: CMOD
Есть у меня для примера экзит EXIT_SAPMF02K_001.
Вот только незадача. Все экзиты CMOD устроены следующими образом: есть стандартная группа функций XF05, в которой есть функциональный модуль EXIT_SAPMF02K_001, в котором есть только строка INCLUDE ZXF05U01, уже в этом инклюде написан весь нужный код.
Вот и вопрос: на что создавать модульный тест?
Его нельзя создать на стандартную группу функций, потому что для этого потребуется её модифицировать, что не есть comme il faut.
Есть варианты.
Можно сделать копии функциональных модулей, так как внутри ФМ только одна строка кода, которая никогда не поменяется. После этого модульные тесты можно писать на эти Z-функции. Этот вариант прост и прям, поэтому и предпочтителен.
Все остальные варианты менее прямы, поэтому менее предпочтительны. Модульные тесты – это не то место, где стоит хитрить без повода.
Грабля третья: ASSIGN наверх
Изредка бывает, что внутри экзита нет каких-либо дополнительных атрибутов передаваемого объекта. И чтобы заполучить их, мы используем хак с ASSIGN следующего вида:
assign (‘(SAPMF05A)UF05A-STGRD’) to <stgrd>.
if sy-subrc = 0.
if <stgrd> = ’02’ .
…
endif.
endif.
И что же может модульное тестирование поделать с таким грубым отношением к области видимости? Ничего.
По возможности избегайте этого (с).
Это серьёзный повод для раздумий. Можно попытаться найти другой экзит, можно попытаться опереться на другие параметры, можно попробовать обеспечить передачу нужных параметров внутри заявленного интерфейса экзита… А можно оставить этот участок кода непокрытым… Пока 100% покрытие – не самоцель, а тестировать нужно сначала то, что может сломаться.
Кстати о “сломаться”. Недавно был случай, что после обновления в стандарте исходная переменная поменяла свой тип, поэтому код в экзите сломался с вытекающими последствиями.
Грабля четвёртая: Доступ к БД
Внутри экзита могут производиться запросы к БД:
if ls_bkpf-awtyp = ‘TRAVL’ and ls_bkpf-xblnr ne space.
select single * from bkpf into ls_bkpf_st
where bukrs = … and xblnr = ls_bkpf-xblnr and awtyp = ‘TRAVL’.
if sy-subrc = 0.
endif.
endif.
Такие вещи всегда считались спорными для модульного тестирования. Однако жить как-то надо.
Кое-что можно сделать, эта грабля не такая жестокая, как предыдущая. Делать запросы к БД – законное желание разработчика, тем более раз уж стандарт предоставляет недостаточно информации в интерфейсе.
Один из способов: переключить соответствующие локальные переменные/структуры на опциональные параметры экзита или глобальные переменные в группе функций. Соответственно в момент теста нужно будет заполнить и их. К сожалению,тут потребуется внести изменения в продуктивный код. Например:
if gs_bkpf_st is initial.
select single * from bkpf into ls_bkpf_st…
else.
ls_bkpf_st = gs_bkpf_st.
endif.
if ls_bkpf_st is initial.
…
endif.
Вариант выглядит стрёмно, опциональный параметр (CHANGING, TABLES) выглядел бы лучше. Но есть пара противопоказаний:
- интерфейс будет отличаться от стандарта
- большое количество запросов к БД будет раздувать интерфейс ФМ
Можно рассмотреть ещё вариант с предварительным заполнением БД необходимыми для теста данными. В некоторых сценариях это имеет смысл: например, если для проводки документа необходимо проверять кредитора на резидентство, то можно просто подсунуть и настоящего кредитора, а не заниматься его симуляцией.
Грабля пятая: Проверка на код транзакции
Иногда в коде экзита можно встретить проверку на код транзакции:
if ( sy-tcode = ‘ASKBN’ or sy-tcode = ‘ASKB’ ) and ls_bkpf-blart = ‘AC’.
…
endif.
В рамках нашей симуляции код транзакции является получается из окружения, а не из интерфейса самого экзита. Потому в модульном тесте SY-TCODE будет показывать транзакцию разработки SE37.
Варианты:
В первую очередь: если подумать, то в некоторых случаях проверку транзакции можно опустить. Часто она бывает избыточной.
Во вторую очередь: если подумать, то в некоторых случаях можно определить транзакцию исходя из других атрибутов. Например, в случае того же экзита 1120 есть признак BKPF-AWTYP.
Ну и напоследок: если уж подрефакторить не удалось, то можно вполне и:
sy-tcode = ‘FB01’.
Будет работать, большого криминала тут не вижу.
На сегодня пока хватит. Снимаю защитный шлем и откланиваюсь.