sy subrc abap что это

Модульные тесты в ABAP. Часть вторая. Грабли

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

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

Первый шаг сделан. Теперь нужно расширить и углубить наше наступление. Глобальная цель – максимально полное покрытие тестами, в рамках целесообразности происходящего. Под пристальным наблюдением — экзиты.

Под катом я приведу несколько примеров граблей, на которые можно наступить.

Грабля первая. Обработка ошибок.

Допустим, наш ФМ делает не замещение значений, а проверку:

Тут есть две проблемы.
Во-первых, если попробовать делать прямой вызов:

То обнаружится, что прогон теста падает с не очень внятным сообщением:

Можно было рассудить, что раз упало, следовательно была ошибка, и значит всё хорошо. Но это не так, потому что тест должен быть зелененьким, а не красненьким.

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

В данном случае исключение происходит в самом движке ABAP Unit, а не в тестирующем или тестируемом коде. Следовательно, необходимо ловить его другим способом.

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

… EXCEPTIONS … error_message = n_error …

Это дополнение предназначено именно для подобных случаев.

И вот мы теперь пишем тест таким образом:

Вот теперь тест проходит правильно.

Во-вторых, из-за того что ошибка нечёткая, то в данном случае мы не можем доказать, что произошла именно нужная нам ошибка. Внутри ФМ может быть запрятано сто двадцать пять разных ошибок на разные случаи жизни. У хорошей ошибки должны быть все необходимые атрибуты: тип, класс, номер, параметры.

Значит нужно немного нарефакторить сам ФМ, причём такой рефакторинг пойдёт ему на пользу.

BTW: Вот это называется “ошибка повышенной чёткости”.

И после этого мы можем дополнить наш тест проверкой:

BTW: в стандартной библиотеке есть много разных уточняющих смысл вариаций метода ASSERT, не видно методов, чтобы подсластить именно такую пачку. Впрочем, можно замутить свой ASSERT, с сахаром и гитхабом.

Грабля вторая: CMOD

Есть у меня для примера экзит EXIT_SAPMF02K_001.

Вот только незадача. Все экзиты CMOD устроены следующими образом: есть стандартная группа функций XF05, в которой есть функциональный модуль EXIT_SAPMF02K_001, в котором есть только строка INCLUDE ZXF05U01, уже в этом инклюде написан весь нужный код.

Вот и вопрос: на что создавать модульный тест?

Его нельзя создать на стандартную группу функций, потому что для этого потребуется её модифицировать, что не есть comme il faut.

Можно сделать копии функциональных модулей, так как внутри ФМ только одна строка кода, которая никогда не поменяется. После этого модульные тесты можно писать на эти Z-функции. Этот вариант прост и прям, поэтому и предпочтителен.

Все остальные варианты менее прямы, поэтому менее предпочтительны. Модульные тесты – это не то место, где стоит хитрить без повода.

Грабля третья: Доступ к БД

Внутри экзита могут производиться запросы к БД, например:

Такие вещи всегда считались спорными для модульного тестирования. Однако жить как-то надо.
Делать запросы к БД – законное желание разработчика, тем более раз уж стандарт не предоставляет достаточно информации в своём интерфейсе.

Один из способов: переключить соответствующие локальные переменные/структуры на опциональные параметры экзита или глобальные переменные в группе функций. Соответственно в момент теста нужно будет заполнить и их. К сожалению, тут потребуется внести изменения в продуктивный код. Например:

Вариант выглядит не очень красиво, опциональный параметр (IMPORTING, CHAHGING или даже TABLES) выглядел бы немного лучше.

Можно рассмотреть ещё вариант с предварительным заполнением БД необходимыми для теста данными. В некоторых сценариях это имеет смысл: например, если для проводки документа необходимо проверять кредитора на резидентство, то можно просто подсунуть и настоящего кредитора, а не заниматься его симуляцией.

Грабля четвёртая: ASSIGN наверх

Изредка бывает, что внутри экзита нет каких-либо дополнительных атрибутов передаваемого объекта. И чтобы заполучить их, мы используем хак с ASSIGN следующего вида:

И что же может модульное тестирование поделать с таким грубым отношением к области видимости? Ничего. По возможности избегайте этого.

Это серьёзный повод для раздумий.
Можно попытаться вырулить как в предыдущей грабле, можно попробовать найти более подходящий экзит, можно попытаться опереться на другие параметры, можно попробовать обеспечить передачу нужных параметров внутри заявленного интерфейса экзита… А можно оставить этот участок кода непокрытым… Пока 100% покрытие – не самоцель, а тестировать нужно сначала то, что может сломаться.

Кстати о “сломаться”. Недавно был случай, что после обновления в стандарте исходная переменная поменяла свой тип, поэтому код в экзите сломался с вытекающими последствиями.

Читайте также:  какие свечи лучше для явы 638

Грабля пятая: Проверка на код транзакции

Иногда в коде экзита можно встретить проверку на код транзакции:

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

Будет работать, большого криминала тут не вижу.

На сегодня пока хватит. Снимаю защитный шлем и откланиваюсь. Спасибо за внимание.

Источник

Запуск SQL запросов в SAP

При внедрении информационных решений на базе SAP ERP, как правило, разворачиваются три системы:

1. Система разработки.
2. Система тестирования.
3. Система продуктивной эксплуатации.

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

Мне удалось насчитать 5 доступных вариантов:

1. Транзакция SE16/SE16N

С помощью этой транзакции можно делать выборку только с одной таблицы. Не подходит для запросов с несколькими таблицами.

Этот инструмент позволяет выполнять SQL-запросы любой сложности, но имеет 2 недостатка:

3. Транзакция SQVI

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

4. Написать простенькую программу с тестируемым запросом и перенести ее в тестовую систему

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

5. Прямой доступ к СУБД

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

Вывод

Получается, что удобного универсального инструмента, который бы позволял оперативно тестировать SQL-запросы любой сложности в SAP, не существует. Придя к такому выводу, я решил разработать такой инструмент.

Приступаем к разработке

Для начала в транзакции SE80 создаем программу ZSQL, GUI-статус MAIN100 с кнопкой «Выполнить» и Экран 0100.

Укрупнённо алгоритм программы выглядит так:

Получение SQL-запроса SELECT

Для получения SQL-запроса будем использовать текстовый редактор, который создадим на экране с помощью класса CL_GUI_TEXTEDIT. Для этого добавим на Экран 0100 пустой контейнер с именем MYEDIT, в который будем выводить редактор.

Парсинг SQL-запроса

Из введенного SQL-запроса нам необходимо получить список выбираемых полей и таблиц для того, чтобы в дальнейшем на основании этого списка динамически сгенерировать структуру ALV-Grid для вывода результата.

Выполнение SQL-запроса

Чтобы выполнить наш запрос, воспользуемся оператором generate subroutine pool, который позволяет динамически генерировать временные ABAP-программы на основании переданного в качестве параметра исходного кода, которым мы подготовим из введенного SQL-запроса.

Вывод результата на экран

Так как состав полей и их тип нам заранее неизвестны, то для получения результата и вывода его на экран нам необходимо динамически сгенерировать внутреннюю таблицу и структуру ALV-Grid на основании выбираемых в запросе полей. Для этого будем использовать метод create_dynamic_table класса cl_alv_table_create.

Полный листинг исходного кода программы ZSQL:

Разработанная программа позволяет выполнять Open SQL-запросы SELECT любой сложности. Только нужно соблюдать одно правило при написании запроса: если используется конструкция COUNT(), то после нее нужно дописывать «AS cnt», чтобы корректно сгенерировался ALV-Grid.

Программу, по идее, можно немного доработать и использовать не только для тестирования запросов, но и для формирования пользовательских отчетов.

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

Источник

Инструкция по использованию отладчика

Венц Власта Александровна

ведущий специалист FI/TR/SL

Использование отладчика (Debugger)

Введение: назначение отладчика

Как известно, отладчик предназначен для пошагового выполнения программ с целью наблюдения за значением переменных и управления их значениями. Его используют при:

Существуют несколько способов запуска исполнения программного кода в режиме отладки:

Рис. 1 Транзакция SE38 –запуск отладчика

Рис. 2 Запуск отладчика в любом окне системы

В том случае, когда известно имя выполняемой программы, удобно воспользоваться ABAP-редактором. Если же имя выполняемой программы неизвестно, либо программа имеет сложную структуру вызова, то удобнее воспользоваться вызовом отладчика с помощью команды «/h».

Вход в отладчик (возможен двумя путями):

Точка прерывания – сигнал в строке кода, который вызывает прекращение выполнения программы на этой строке и запускает ABAP-отладчик.

Перезапуск отладчика

Выключение отладчика (продолжить выполнение программы в обычном режиме)

Выход из отладчика с выходом из программы

Выход из режима отладки с последующим выполнением программы имеет особенность – режим отладки может быть возобновлен в случае наличия точек прерывания в модуле программы.

Читайте также:  блоки фск что это

Интерфейс

Отображение исходного кода

Позиционирование на указанном столбце кода

Позиционирование на указанной строке кода

Увеличение фрагмента кода

Позиционирование на текущем операторе

Доступные способы отображения данных

Управление отладкой

Позволяет выполнить оператор в текущей строке с заходом в вызываемую подпрограмму/функцию/программу (Рис. 3)

Рис. 3 Отладчик

Позволяет выполнить оператор в текущей строке с обходом вызываемой подпрограммы/функции/программы

Возвращает из вызываемой подпрограммы/функции/программы в главную программу

Запускает выполнение программы до следующей точки прерывания

Просмотр/изменение значений полей

Нажмите Enter, значение поля отобразится.

Так же можно отобразить значение поле для просмотра двойным щелчком по этому полю.

Sy-subrc –- системная переменная, хранящая код возврата: результат выполнения какого-либо действия. 0 – действие выполнено успешно. Другие значения зависят от исполняемого оператора.

Sy-tabix – текущий индекс строки, читаемой внутренней таблицы.

Sy-dbcnt – число считанных строк из БД

Sy-dynnr – номер экрана.

Просмотр/изменение внутренних таблиц

Для отображения внутренних таблиц переключитесь в режим просмотра таблиц (нажмите кнопку ) и скопируйте название таблицы в поле «ВнутрТаблица».

Прочие функции

Если хотите прочитать статью полностью и оставить свои комментарии присоединяйтесь к sapland

Источник

ABAP Blog

Все о разработке в решениях от SAP

ABAP Blog

Все о разработке в решениях от SAP

Ссылки

Цитаты

Вы работаете с чистым кодом, если каждая функция делает примерно то, что вы ожидали. Код можно назвать красивым, если у вас также создается впечатление, что язык был создан специально для этой задачи.

У. Каннингем

Новое

Последние комментарии

Обработка особых ситуаций в ABAP

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

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

В ABAP есть два основных способа работы с исключениями, классический способ заключается в вызове особых ситуаций описанных в ФМ или методе на отдельной закладке:

Классический способ может использоваться и в классах:

Новый способ основывается на ООП, где в качестве исключений используются классы (обратите внимание, что установлена галочка – классы исключений):

Хочется отметить, что новый способ был введен с версии SAP Web AS 6.10 и при создании новых функциональных модулей или методов рекомендуется использовать именно его. В данной статье не рассматриваются системные исключения и их обработка до введения классов исключений.

В RFC модулях в настоящее время используется классический способ обработки исключений. Не допускается одновременно использовать классический и основанный на классах, способы обработки исключений (в интерфейсе методов, процедур, функций).

Классический способ обработки исключений

При вызове исключения, системное поле sy-subrc будет заполнено номером, под которым исключение было обозначено при вызове ФМ, метода или процедуры:

Как правило, исключения вызываются с текстом сообщения, данный текст может быть описан статически – при вызове исключения оператором MESSAGE, либо динамически – путём получения текста из описания ФМ.

Так же исключение может быть вызвано без какого-либо текста (оператором RAISE ИмяИсключения), но данный способ лучше не использовать, т.к. вызов исключения должен как-то себя расшифровывать и говорить о том, что собственно произошло.

Напишем небольшой ФМ, рассчитывающий сумму двух чисел, оба параметра помечены как необязательные, если первый параметр не будет задан при вызове ФМ, система выдаст исключение – no_num_1.

И программа для его вызова:

При запуске программы произойдет вызов исключения, т.к. был использован тип сообщения «Е», программа завершит свое выполнение после показа сообщения:

Замечу, что это вовсе не означает, что при вызове ФМ или метода и обработке исключения необходимо завершать работу программы, вы можете свободно продолжить её выполнение и далее, добавив например, сообщение об ошибке в лог программы, а не на вывод как в примере.

Ключевое слово OTHERS используется для того чтобы поймать исключения не описанные в ФМ или явно неуказанные, при вызове ФМ.

Пример вызова неописанного исключения:

В данном примере вызывается неописанное в интерфейсе ФМ исключение – no_num_2, которое будет благополучно поймано с помощью ключевого слова OTHERS (системное поле sy-subrc примет значение равное 2).

Кроме того, можно не обрабатывать большой список всех возможных исключений описанных в ФМ, тогда в случае если такое исключение будет вызвано поле sy-subrc примет значение, указанное в OTHERS.

В ФМ, могут быть добавлены новые исключения и в случае, когда при вызове ФМ они не обработаны и не указано слово OTHERS программа упадет в дамп с ошибкой времени выполнения — RAISE_EXCEPTION. Отсюда вывод, ключевое слово OTHERS подставляем всегда, при вызове ФМ (метода или процедуры), когда мы точно не уверены в неизменности компонента.

При вызове исключения в процедурах (perform…) из ФМ, система пытается найти и вызвать исключение в первом ФМ из стека вызовов, если исключение не найдено, вызывается так же, как и неопределенное исключение в ФМ.

Читайте также:  Что такое несчастный случай в страховании определение

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

ФМ будет выглядеть следующим образом:

Иногда особые ситуации используются не как исключения, а как параметры показывающие обработку ФМ и его результат, возвращаемый в поле sy-subrc, хотя лучше бы пренебречь подобным стилем:

Сообщения, вызываемые в ФМ или методах, оператором MESSAGE, без дополнения RAISING, либо сообщения вызываемые системой (например, при обработке экранов), могут быть обработаны программой с использованием дополнения: error_message = n_error, указываемого так же после ключевого слова EXCEPTIONS.

При обработке сообщений:

Обработка исключения классическим способом может быть выполнена динамически, с помощью ключевого слова EXCEPTION-TABLE. Пример:

Обработка исключений, основанная на классах

Как понятно из названия, под исключениями в данном случае понимаются объекты специальных классов исключений. Вызов такого исключения может быть выполнен либо в программе с помощью оператора RAISE EXCEPTION, либо системой (например, при делении на ноль будет вызвано предопределённое исключение CX_SY_ZERODIVIDE, список таких исключений), либо через дополнение THROW в условных выражениях (с версии ABAP 7.4).

Во всех случаях инициируется создание объекта указанного класса (если указано дополнение INTO в CATCH), в атрибутах которого содержится информация о возникшей исключительной ситуации, доступ к ним, как правило, осуществляется через методы этого класса.

Классы особых ситуаций могут быть определены как локально, так и глобально через построитель классов – транзакция SE24, диалог создания:

В данном случае галочка «с классом сообщений» означает использование в качестве текста сообщения из класса сообщений транзакция SE91 (будет рассмотрено ниже). По умолчанию текст сообщения создается в текстах класса:

Категории исключений

Все классы особых ситуаций являются производными одного из классов: CX_NO_CHECK, CX_DYNAMIC_CHECK или CX_STATIC_CHECK, которые сами являются производными общего суперкласса CX_ROOT.

На исключения накладываются следующие ограничения:

Небольшой пример с локальным классом исключения:

Источник

ABAP Blog

Все о разработке в решениях от SAP

ABAP Blog

Все о разработке в решениях от SAP

Ссылки

Цитаты

Ничто так не раскрывает недостатки проектирования как реализация.

Новое

Последние комментарии

ABAP bad practice

По своему роду деятельности часто приходится разбираться с чужим ABAP кодом, в котором постоянно встречаются одни и те же проблемы, вызывающие «головную боль» при сопровождении. В данной статье будут рассмотрены основные из них.

UPDATE. На сайт добавлен раздел с лучшими практиками.

Незнание основополагающих принципов разработки

Описанные далее принципы не относятся напрямую к языку ABAP и применимы так же к другим языкам.

KISS принцип

Существует множество расшифровок данного принципа:

Проще говоря, программный код должен состоять из как можно более простых для понимания и сопровождения блоков. Не должно быть «портянок» по 10 тыс. строк подряд, особенностью такого кода является увеличение вложенности условных конструкций и общее усложнение логики работы. Относительно гайдлайна по ABAP, процедура или метод должны содержать не более 150 выражений.

На приведенном ниже рисунке (из официальной документации ABAP) показан пример того, как после рефакторинга 1 метод со сложной логикой был разделен на 3 отдельных.

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

В данном примере можно выделить запись истории в отдельную процедуру, которая будет отвечать именно за запись журнала:

При необходимости изменения таблицы с журналами, вам не придется менять остальные процедуры в которых вызывается процедура записи истории.

Разделение ответственности (SoC)

Разделение ответственности (separation of concerns) говорит о разделении программы на функциональные блоки и о том, что эти функциональные блоки не должны перекрывать друг друга относительно своих функций. Взаимодействие между такими блоками должно быть через определенные для этого интерфейсы. Разделение ответственности позволяет снизить системную сложность, повысить надежность и адаптивность программ, а также обеспечить возможность их повторного использования.

В качестве примера рассмотрим стандартный пример из справки ABAP:

В данном примере видно классический образец портянки на её начальной стадии (для столь простых программ как в примере, соблюдение принципа не является необходимостью, однако, когда речь идет больших программах, его нарушение чревато проблемами при сопровождении). Программа состоит из нескольких логических блоков: получения, проверки (обработки) и отображения данных, однако все эти блоки слиты воедино в обработке START-OF-SELECTION (не явно).

Далее приведен пример того, как программа была разделена относительно блоков, отвечающих за конкретные действия с соблюдением принципа:

YAGNI

Сокращение от английского (You Ain’t Gonna Need It – вам это не понадобится). Принцип, который декларирует в качестве основной цели отказ от избыточной функциональности или от добавления функциональности, в которой нет необходимости.

Желание написания кода, который может потребоваться в будущем приводит к следующим последствиям:

Пример нарушения, с которым часто приходится сталкиваться:

Источник

Информ портал о технике и не только