Эта статья предназначена для разработчиков ABAP в системах SAP ERP. Он содержит множество проблем, специфичных для платформы, которые малоинтересны или даже спорны для разработчиков, использующих другие платформы.
Это третья часть публикации.
Начало можно прочитать здесь: Модульные тесты в ABAP. Первая часть.
Первый тест Модульные тесты в ABAP. Часть вторая.
Грабли
Мы измерим себя
Считается, что основной метрикой качества тестирования является охват. В развивающем Интернете часто можно встретить формулировки в стиле «полный охват».Как правило, под полным покрытием подразумевают некие абсолютные 100,00%.
Процент охвата — цифра сомнительная, ровно такая же сомнительная, как и «средняя температура по больнице».
Процент покрытия проекта — это среднее покрытие его частей.
То есть: Модуль-1 имеет охват 80%, Модуль-2 имеет охват 20%, в среднем охват будет 50%, при условии, что модули примерно равны по содержанию.
Правда ли, что 80% в четыре раза лучше, чем 20%? Среднее значение варьируется.
В ABAP UNIT есть три разных показателя покрытия: по процедурам (охват процедур) согласно инструкции (покрытие заявления) покрытие филиалов Например, есть класс, группа функций или пул подпрограмм:
Н.form do_something. c = a. d = b. endform. form do_something_else. if a > b. c = a. d = a. else. c = b. d = b. if d > 1000. d = 1000. endif. endif. endform. form do_nothing. if 1 = 2. c = d = 0. endif. endform.
Б.
Пул подпрограмм легче продемонстрировать, чем группу функций или класс с методами.
Пул подпрограмм описывается значительно меньшим количеством букв, чем класс.
Параметры взяты из определений.
В этой небольшой демонстрации нет существенной разницы.
И вообще: все переменные фиктивные, любые совпадения с продуктивным кодом случайны.
.
И предположим, что мы написали по одному простому тесту для каждой подпрограммы, функции, метода.
Для всех подпрограмм мы будем использовать значения [A = 7, B = 77].
class lcl_test definition for testing
duration short
risk level harmless.
private section.
methods: setup.
methods: do_something for testing.
methods: do_something_else for testing.
methods: do_nothing for testing.
endclass.
class lcl_test implementation.
method setup.
a = 7.
b = 77.
endmethod.
method do_something.
perform do_something.
endmethod.
method do_something_else.
perform do_something_else.
endmethod.
method do_nothing.
perform do_nothing.
endmethod.
endclass.
NB: пусть пока будет общая инициализация и не будет проверять результат. .
Охват процедуры
Это самый простой случай, его можно по пальцам пересчитать.
Покрытие процедур составит 100% = (1+1+1)/(1+1+1)*100.
Покрытие заявлений
Что если посчитать количество инструкций для одних и тех же процедур? Каждая процедура содержит разное количество инструкций.Более того, при заданных входных параметрах будут вызываться не все инструкции: DO_SOMETHING: три инструкции из трёх были обработаны DO_SOMETHING_ELSE: обработано пять инструкций из восьми.
DO_NOTHING: две инструкции из трёх были обработаны Инструкции считаются просто: обычные инструкции, сама процедура считается инструкцией, условие считается инструкцией.
Предложение ENDIF не считается инструкцией, поскольку оно указывает только место перехода и не связано с какими-либо вычислениями или действиями.
Если рассчитать метрику по инструкции, то она составит 71% = (3+5+2)/(3+8+3)*100.
Давайте посмотрим, как метрика работает на DO_SOMETHING_ELSE. Инструменты разработки ABAP могут раскрашивать строки кода в соответствии с метрикой:
Наглядно, быстро, понятно.
Просто потрясающе, я даже не ожидал такого от ABAP. Из этой раскраски становится очевидным, что если бы мы взяли другие исходные параметры, процент покрытия мог бы быть другим.
В случае [A = 77, B = 7]:
Становится очевидным, что полного охвата этой метрики можно достичь только при использовании более чем одного сценария тестирования.
Например, при двух тестах [A=77, B=7] и [A=7, B=7777] все становится зеленым:
Таким образом показатель достигает 100%.
Вы можете успокоиться на некоторое время.
Покрытие филиалов
Эта метрика работает немного сложнее.Он берет все инструкции, которые могут вызвать ветвление, и проверяет их, чтобы убедиться, что каждая такая инструкция выполняется в обоих направлениях.
Давайте посмотрим на последний пример: Первая инструкция [IF A > B] сработала дважды на двух тестах: один раз для TRUE [A = 77, B = 7] и один раз для FALSE [A = 7, B = 7777].
Но вторая инструкция [IF D > 1000] сработала только один раз на TRUE [A = 7, B = 7777].
Сам вызов функции считается безусловным, плюс первое ЕСЛИ дает два из двух, второе ЕСЛИ дает только одно из двух.
Это значит, что наша метрика будет равна 80% = (1+2+1)/(1+2+2)*100. И тут получается, что для одной функции двух тестов уже недостаточно, а нужны три.
Вы также можете добавить скрипт [A = 7, B = 77] к предыдущим двум, чтобы второй IF выполнялся со значением FALSE. После добавления третьего сценария метрика этой функции достигла 100%.
Вы спросите, а как насчет DO_NOTHING? Не существует теста, гарантирующего, что метрики для ветвей или инструкций равны 100%.
Очевидно, функция требует рефакторинга, без которого добиться полного покрытия не удастся.
Эту функцию следует либо удалить, либо изменить ее с DO_NOTHING на DO_SOMETHING_COMPLETELY_DIFFERENT.
На сто процентов!
Жаль, что нельзя написать еще больше тестов и получить больше 100%.Понятно, что метрика «Покрытие процедур» менее информативна в деталях.
Присмотреться к нему можно только на ранних стадиях, если кода много и тестов почти нет. Но на какой из двух оставшихся показателей нам следует обратить пристальное внимание в следующий раз? Если первая метрика просто показывает, насколько широко вы осветили функциональность, то вторая показывает, насколько хорошо вы ее осветили.
Как вы заметили, по инструкциям можно получить 100%, но не 100% по веткам.
Но не наоборот (или я не могу придумать такого примера).
Если вы уже получили 100% по веткам, то вы зашли во все закоулки и выполнили все инструкции.
Но кому-то может показаться, что метрика ветвей в среднем дает менее показательные весовые коэффициенты, поскольку игнорирует один из очевидных весовых показателей — количество строк кода, то есть количество инструкций.
Кстати: Да, пустая процедура дает 100% результат!
Соглашение есть соглашение
Для работы ABAP Unit не важно: сколько вообще у вас тестовых классов; как называется тестовый класс; где он находится? Как называются его методы? Главное, чтобы локальный класс: был доступен; имел прозвище «на пробу»; были методы с никами «на пробу».Но, с другой стороны, даже имена переменных тоже не являются случайным набором букв.
Следовательно, у нас должно быть какое-то общее условное согласие по каждому пункту, облегчающее общее восприятие картины.
Как соглашение об именовании или форматировании.
Что?
Тестовых классов должно быть ровно столько, сколько необходимо.Как минимум, каждый крупный объект (группа функций, программа, класс) должен иметь один тестовый класс, можно и больше.
Если у вас простая группа из нескольких связанных функций, то для нее достаточно одного класса.
Но если в вашей группе шесть пакетов слабо связанных между собой функций, то здесь скорее должен возникнуть вопрос: «Сколько групп функций должно бытьЭ», и это тема совсем другого разговора.
Правильно ответив на этот вопрос, вы можете принять метод НАСТРОЙКИ в качестве критерия делимости.
В классе должен быть один такой метод; он вызывается автоматически перед каждым методом тестирования.
Каждый скрипт должен предоставлять отдельный метод тестирования, имя метода должно быть непосредственно получено из тестируемого кода.
Где?
Один из принципов модульного тестирования заключается в том, что тестовый класс должен тестировать только тот код, в чьей юрисдикции он находится.И хотя тесты могут располагаться в любом месте исходного кода, стоит отделить от тестов рабочий функционал.
Здесь мастер групп функций создает отдельную программу включения по заранее заданному шаблону: например: LZFI_BTET99 для группы функций ZFI_BTE. Я не вижу в этом ничего плохого, надо взять это за образец и продолжать в том же духе.
Также в программах типа REPORT: тесты пишите строго в одной отдельной включаемой программе, с именем по шаблону.
Однако я не могу никому запретить писать все вперемешку: код, его тест, код, его тест.
Когда?
Вы не можете запускать полный цикл модульных тестов каждые пять минут. Но, как минимум, перед тем, как отпустить запрос, необходимо запустить тест задействованных объектов.
Позвольте мне подвести итог
Просто несколько тезисов, чтобы подвести черту: Вы можете жить с этим.Тестовый код больше продуктивного кода.
Во многих случаях подходы TDD оправданы и рекомендуются к использованию.
Просмотр существующего продуктивного кода без тестов вызывает значительную нагрузку на мозг.
Если вы попытаетесь покрыть тестами уже написанный код, без рефакторинга зачастую не обойтись.
А рефакторинг — это немного другая и более сложная задача, чем само тестовое покрытие.
Рефакторинг можно отложить до тех пор, пока вы не сделаете с кодом что-нибудь еще.
Если у вас продуктивный код, который не меняется годами, то покрывать его тестами следует в последнюю очередь.
Код может остаться непокрытым из-за замкнутого цикла: вы не можете выполнить правильные тесты, потому что сначала нужно провести серьезный рефакторинг, а делать рефакторинг не рекомендуется до тех пор, пока не закончатся тесты.
В некоторых случаях покрытие тестированием может оказаться невозможным.
Бывает. Смиритесь.
Некоторые показатели охвата гораздо легче достичь 100%, чем другие.
Это не значит, что нужно делать то, что проще.
Никаких тестов в стандартном коде системы я не заметил, а если бы они и были, то их выполнение было бы запрещено.
В суете не забывайте главное: тесты не являются самоцелью.
Все должно быть выгодно.
Прямая реальная польза от тестов будет только в те моменты, когда со временем тесты провалятся, когда кто-то допилит этот функционал.
Потому что научиться правильно падать – лучший способ избежать травм.
Если это актуально для каратистов и велосипедистов, то и для программистов это будет полезно.
Лучше упасть правильно, плохо крутя педали, чем упасть неправильно, крутя педали хорошо.
Знать, как правильно падать, важнее, чем иметь подходящее снаряжение.
Но сейчас вы можете получить только косвенную выгоду: Тесты документируют варианты использования Тесты помогают выявить области, требующие внимания (рефакторинг).
Тесты помогают выполнять базовые проверки в тех областях, которые сложно протестировать вручную.
На сегодня все, увидимся снова.
Теги: #sap #abap #tdd #ERP-системы
-
Ноутбук Dell Studio 15
19 Oct, 24 -
Международный Валютный Фонд (Мвф)
19 Oct, 24 -
Внезапные Документы
19 Oct, 24 -
Нужна Ли Аспирантура?
19 Oct, 24 -
Верхняя Пышма: В Конце Года
19 Oct, 24 -
Не Пора Ли Яндексу Сделать Редизайн?
19 Oct, 24