Некоторые утонченные приемы отладки кода в 1С 8.0 Автор статьи: Гений 1С | Редакторы: Волшебник, Neco
Последняя редакция №21 от 17.01.08


Ключевые слова: отладчик, отладка, управление, точка останова, пошаговое выполнение


Те, кто хоть раз работал с отладчиком VBA, мечтают о том, чтобы и в 1С можно было изменять значения переменных и переходить на любую точку кода.

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

Применение этих функций основано на том, что в табло отладчика в режиме Конфигуратора или 1С:Предприятия можно вызывать доступные в контексте точки останова функции. Примеры нужно вводить в табло Ctrl+Alt+W или в окно просмотра значения выражения Shift+F9 и сразу же получать результат.

Функция ДУ



Эта функция позволяет в любой момент выполнить любой код на языке 1С над любыми данными, переданными ей.

Функция Ду(Код, П=Неопределено, П1=Неопределено, П2=Неопределено, П3=Неопределено, П4=Неопределено) Экспорт
Перем Р;
Выполнить(Код);
Возврат Р;
КонецФункции


Примеры:
= Сообщает некий текст
Ду("Сообщить(1)")
= Присваивает переменной Отказ значение истина
Ду("П=истина", Отказ)
= Закрывает форму
Ду("П.Закрыть()", ЭтаФорма)
= В отладчике нельзя вызвать процедуру, но можно это сделать через ДУ:
Ду("ЗавершитьРаботуСистемы()");

Функция Присвоить



Всем известно, что в 1С80 нельзя по хоту отладки менять значения переменных.
Однако есть выход!
В общем модуле объявите функцию:

Функция Присвоить(А,Б) Экспорт
А=Б; Возврат А;
КонецФункции

Теперь вы можете в любой момент присвоить значение переменной.

Примеры:
Присвоить(флПродолжать, ложь);
Присвоить(Остаток, ОстатокНаСкладе()-11);

Отладка в типовой конфигурации



А что же делать, если вам досталась отладка конфигурации, в которой нет этих замечательных функций?

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

ВнешниеОбработки.Создать("C:\debug.epf").Присвоить(А, Неопределено);

Манипуляции со стеком.



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

Нужно открыть окно стека (Ctrl+F3), перейти на нужны уровень и ввести в табло имя переменной.
Лучше всего это рассмотреть на примере рекурсивной функции:
Код 1c:
Функция Тест(А)
    Если А>10 Тогда
        Возврат ложь;
    Иначе
        Возврат Тест(А+1);
    КонецЕсли;
КонецФункции

Поставьте в этой функцию точку останова и вы увидите что на разных уровнях стека переменная А принимает разные значения.

Прерывание работы программы



К сожалению, в 1С 80 можно прекратить работу некоторого кода только прекратив работу всего 1С:Предприятия. Так сказать, для борьбы с головной болью нужно отрубить голову.
Но не все так плохо.

С помощью функции Присвоить вы можете присвоить какому-нибудь критическому объекту программы значение Неопределено или ноль и как только программа попробует получить реквизит или метод этого объекта возникнет ошибка и работа кода прекратится.
Например вы находитесь в точке:

А=1;
Если Спр.Код>А Тогда
Возврат Неопределено;
КонецЕсли;

Используйте вызов:
Присвоить(Спр,0);

Теперь, как только выполнение кода дойдет до строки с "Если", возникнет ошибка и выполнение прекратится.

Упреждающий просмотр



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

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

Изменение кода на лету



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

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

Маялись мы маялись, а потом придумали - все вызовы Выполнить были вынесены в одну функцию, куда передавался код для выполнения и параметры. Это нам и сослужило хорошую службу.

Мы вставили Выполнить в Попытка-Исключение и если происходило исключение, предлагали программисту вживую изменить код. Если он соглашался, открывался диалог ввода кода, где он мог заменить старый код на новый. И перед выполнение кода мы проверяли, имеется ли он в списке замен. Если имеется, то мы перед выполнением подменяли старый код на новый. Так нам удалось быстро загрузить данные.

Отладка на сервере



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

Условная точка останова



Не все знают, что в 1С 80 есть условная точка останова - точка останова по условию. Однако это очень полезный механизм.

Трассировка



Иногда возникает необходимость в трассировке кода программы - т.е. в выдаче в окошко сообщений значений переменных на каждом проходе через точку кода.

Для этих целей в 1С можно использовать условную точку останова, т.к. условие проверяется на каждом проходе кода через условную точку останова.

Рассмотрим код:
Код 1c:
С=0;
Для Инд=1 по 10 Цикл
    С=С+Инд;
КонецЦикла;   //Здесь ставим условную точку останова

На указанной строке ставим точку останова с условием:
Код 1c:
ДУ("Сообщить(""Сумма:""+П)", С)

Теперь при отладке программы в окошке сообщения трассируется выполнение кода:

Сумма:1
Сумма:3
Сумма:6
Сумма:10
Сумма:15
Сумма:21
Сумма:28
Сумма:36
Сумма:45
Сумма:55

Естественно, можно использовать условия и выводить не все сообщения, а только при интересующих нас значениях переменных:
ДУ("Если Сумма>10 Тогда Сообщить(""Сумма:""+П) КонецЕсли", С)


Метод удобен тем, что не нужно вносить изменения в конфигурацию.
Удобно ловить ошибки, когда 1С "вылетает", если записывать сообщения в файл.

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


Предположим у нас есть такой код:
Если А=0 Тогда
ИначеЕсли А=1 Тогда
ИначеЕсли А=2 Тогда
КонецЕсли;
В таком случае мы можем применять программное управление кодом.
На начале оператора Если ставим условную точку останова:
?(А=1, Присвоить(А,2), Присвоить(А, 1))
Т.е. если А=1 то мы присваиваем А значение 2, и присваиваем 1 в противоположном случае.
Это позволяет, не меняя конфигурацию, постоянно перенаправлять код на нужную нам ветку.
Можно просто поставить условную точку останова, которая будет присваивать А нужное значение:
Присвоить(А,2)

Обозримая трассировка



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

Предлагаю оформлять такие вызовы так, чтобы перед вызовом сообщения стояла точка с запятой:
Код 1c:
;Сообщить("Сумма="+Сумма);

Если трассировка временно не нужна, ее нужно убрать так:
Код 1c:
//;Сообщить("Сумма="+Сумма);
 
 
Тогда все активные трассировки можно найти по строке ";Сообщить", а все неактивные - по строке "//;Сообщить".

Интерфейс для отладки


Честно говоря, когда мне надоело постоянно после перезапуска 1С заходить через Операции-Документы в список нужных мне документов, я создал себе интерфейс "Отладчик" и в его меню воткнул нужные мне команды. Теперь после перезапуска я оказывался в нужном мне журнале/форме с одного клика.

Другой вариант - создать себе целый отладочный десктоп - т.е. сразу открыть все нужные формы и документы. Для этого лучше всего создать внешнюю обработку, назвать ее например "Открывалка" и в форме этой обработки написать, что нужно открывать:
Код 1c:
Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)
    Документы.ПриходнаяНакладная.ПолучитьФормуСписка().Открыть();
    Отказ=истина;
КонецПроцедуры

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

Более простой вариант для ленивых - в табло написать вычисление выражений (например с помощью ДУ), которые откроют нужные документы и журналы. Легко и быстро!

Еще один простой вариант - использование истории отборов. Тогда вам нужно только сделать отбор по нужному документу, обязательно закрыть 1С крестиком, а не через прекращение отладки (чтобы сохранились условия отбора), а затем после запуска 1с зайти в нужный список и нажать историю отбора.

Отладка клиент-серверной базы


Известно, что код на сервере не отлаживается.
Поэтому варианты отладки:
1. Трассировка (вставка диагностических сообщений).
2. Выгрузить базу в файловую копию и там отлаживать.
3. Поставить галочку "Клиент" на интересующем вас модуле и отлаживать. Потом вернуть галочку обратно.
Примечание: В 1С v 8.1 появилась возможность отлаживать код на сервере. Для этого сервер нужно запустить в режиме отладки, можно из командной строки: ragent.exe /debug
Использование внешней обработки


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


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


Иногда нужно посмотреть, как ведут себя два параллельных процесса.
Простейший способ отладки таких ситуаций - вставить в коде вызов процедуры Предупреждение().
Например, в событии ПриЗаписи объекта вставляем вызов Предупреждение("Идет запись объекта!!!").
Тогда если открыть другую сессию и попытаться записать объект, выдастся предупреждение, что объект заблокирован.

Если такая отладка вызывается часто, рекомендую такой способ вызова сразу двух сессий 1С.
Из отладчика нажимаете F5 (Запустить отладку), запускается 1С:Предприятие. Отключаетесь от отладки этого 1С Предприятия - "Отладка"->"Отключиться", затем еще раз нажимаете Ф5. В итоге вторая сессия у вас подключена к отладчику. Запускаете код с предупреждением в первой сессии и отлаживаетесь во второй.

Ускорение отладки


Отладчик снижает скорость работы программы.
Поэтому можно поступить так - отключить отладчик, а в нужном месте вывести Предупреждение();
Когда выведется предупреждение, можно опять подключить отладчик, поставить точку останова и начать отладку.

Поиск точки останова


Иногда сложно найти, в какую процедуру заходит программа по нажатию кнопки. В таком случае выбирайте команду отладчика "Остановить" и нажимайте кнопку. Программа остановится на первой же строке кода. У метода есть недостаток - если подключен обработчик ожидания, то программа может остановиться на нем, а не на коде кнопки, если код обработчика ожидания сработает раньше. ;-)