Эта статья ориентирована на ABAP-разработчиков в системах SAP ERP. Она содержит много специфических для платформы моментов, которые малоинтересны или даже спорны для разработчиков, использующих другие платформы.

В умных книгах и статьях много про это написано в целом. Но вопрос по части специфики в ABAP-программировании раскрыт мало.

ABAP-программирование может быть совсем разным. Но почти в любом большом проекте его можно разложить на следующие кучи:

  • Экзиты (user-exits). Сюда относятся: проверки, замещения, BTE (Business Transaction Events), BAdI, CMOD и подобные способы расширения стандартной функциональности.
  • Собственное приложение. Вполне вероятно, что это будет вариация на тему CRUD.
  • Отчеты. Можно сказать, что отчёт – это такое собственное приложение, но у программ такого рода есть свои нюансы.
  • Входящая интеграция, исходящая интеграция. Мы вызываем, нас вызывают, как это часто не совпадает.
  • Вспомогательные библиотеки. Полуфабрикаты, необходимые для построения готового продукта.

И сейчас отдельно про экзиты.

Часть первая. Первый тест


Экзит – это отдельный метод класса или функциональный модуль строго определенного интерфейса с вашим ABAP-кодом, который вызывается в определённых бизнес-операциях (транзакциях) в некоторый определённый момент. Вроде плагина.

Классический случай: функциональный модуль замещения без глобальных данных. И пусть примером нам будет событие BTE 1120 (замещение при проводке бухгалтерского документа).

В случае экзитов, обычно тест заключается в выполнении пользовательской операции, которая связана с этим событием. Мы могли бы симулировать эту пользовательскую операцию, сохранить документ, и потом проверить этот документ на требуемые свойства. Но в том-то то и заключается одно из важных отличий модульного тестирования от обычного тестирования, что здесь так действовать не нужно.

У нас есть функциональный модуль с несколькими входными параметрами и несколькими выходными параметрами. Мы что-то подаём на вход, и на выходе получаем какое-то изменение.

Значит наш модульный тест должен быть таким:

  • готовим набор входных параметров, который симулирует нужный нам эталонный документ
  • запускаем наш функциональный модуль
  • проверяем, что выходные параметры содержат требуемые значения

Допустим, изначальная постановка была следующей:
Если проводится бухгалтерский документ вида VB и в позициях идёт проводка по дебету счёта 1080, то весь документ должен провестись с признаком “Красное сторно”.

Можно применить и TDD, но мы (пока) такую методологию не будем брать на вооружение.

В итоге мы написали в ФМ ZFI_BTE_00001120 некоторый код:

image

Код готов, мы хотим теперь написать тест для него.

Варианта два:

  • запускаем мастер
  • делаем всё ручками

Я считаю мастер сделан почти с человеческим лицом, годный.

Сначала посмотрим на мастер, для этого заходим в группу функций и дальше по меню “Создать – Другие объекты – Сгенерировать тестовый класс” и идём по шагам.

Класс создаётся не для конкретного ФМ, а для группы функций целиком:



Можно придумать имя для класса и поставить какие-то галочки:



Выбираем, какие именно функциональные модули нам нужны:



Далее, далее, далее… Смотрим, что нам мастер нагенерировал:



Методы SETUP и TEARDOWN пустые. Движок будет запускать их соответственно в начале и в конце каждого теста.

К каждому выбранному функциональному модулю был сгенерирован тестовый метод строго по имени нашего ФМ.

И реализация базовой проверки в виде простого вызова уже есть:



Как видите, ничего сверхъестественного мастер не сделал, значит мы можем и сами такие заготовки делать.

Если теперь накидать вокруг этого кода тест именно для нашего бизнес-сценария, то мы подойдём к промежуточному итогу:



Я полагаю, что не обязательно полностью симулировать документ, если это не влияет на работу всего комплекса тестов: достаточно предоставить только самое необходимое для работы бизнес-сценария. Поэтому можно опустить даты, суммы, наличие кредитора, вид счёта и тому подобные параметры.

Получился годный рабочий сценарий, планирую использовать в боевой обстановке.

Можно накидать тесты и для других функциональных модулей в группе функций.

Теперь мы можем запускать модульные тесты по меню “Функциональный модуль – Выполнить – Тесты модулей”:



Тихое, маленькое, зелёненькое, всё хорошо. А если бы мы ошиблись или в тесте, или в самом ФМ, то картина была бы такая:



Всё сломалось! Что и требовалось доказать.

BTW: Вот наконец-то, есть применение табличным функциям! В моём текущем активном проекте большой апгрейд всё-таки произошёл, и теперь вместо старинных APPEND и READ можно писать такие вкусные штуки.

BTW: Там же рядом есть подпункт “С измерением покрытия”, но до него мы ещё доберёмся.

BTW: Да, есть огрехи в русской версии, не будем их осуждать.

На сегодня пока хватит…
Продолжение можно прочитать тут: Модульные тесты в ABAP. Часть вторая. Грабли

Комментарии (6)


  1. kanikeev
    18.12.2015 13:57

    Хм… в задании у вас

    дебету счёта 1080

    а в коде
    hkont(5) = '00108'


    1. ivanbolhovitinov
      18.12.2015 14:15

      Есть такое допущение. Это уже внутренняя кухня, счет технически 10 знаков, из них 8 знаков используются, только цифры, значит два нуля спереди, 1080 счёт групповой, обозначает группу, и… счёт превращается… превращается счёт… из 1080 в диапазон 0010810000-0010849999, что в целом эквивалентно.


  1. AndreySu
    18.12.2015 16:19
    +1

    t_bkpf bsec zfi_bte_000124, этим все сказано! Сразу стало понятно!


    1. ivanbolhovitinov
      18.12.2015 16:33

      Ну я так сразу и предупредил в первом абзаце. Объяснения на тему «что такое BKPF и и почему BTE к нему именно за номером 1120, а не 124» могли бы лечь в основу отдельной статьи, которая будет иметь очень косвенное отношение к сабжу.


      1. AndreySu
        18.12.2015 16:37

        Не, я вообще о программировании в ABAP. А не о терминах.


    1. smartello
      20.12.2015 15:58

      Любой консультант с хоть каким-нибудь опытом работы с SAP FI сразу предположит для какого вызова этот функциональный модуль написан (хотя ему всё-равно нужно будет запускать настройку и проверять), а так же что хранится в перечисленных таблицах.

      PS: и хорошо ещё что так, а не Belegkopf (bkpf, заголовок документа) и Belegsegment (bseg, позиции документа) ;)