Неблагодарное это дело – выдавать сообщения об ошибках

28.09.13

Разработка - Тестирование QA

Методика формирования и выдачи сообщений об ошибках. Описывается способ работы над ошибками в данных, прилагается программный код. Приводятся примеры.

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

Это хороший тест, проверьте себя. Прагматы выбирают первый вариант, зануды (не в обиду) -  второй, а гении … - вообще игнорируют Smile.

Это сообщение адресовано второй категории, к которой отношу и себя.  Итак, выбор сделан, решено  дать развернутое сообщение об ошибке. Но вот незадача – в той процедуре, в которой возникла ошибка, нет сведений для развернутого сообщения. Не беда. Добавляем параметры в процедуру и передаем в них недостающие сведения. Но и тут проблемы. В вызывающей процедуре имеется только часть этих сведений. Не очень радует, а что делать?

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

Куда вставить эту процедуру? Можно в какой-нибудь общий модуль, можно в разные модули, где она понадобится. Например, в модуль управляемой формы, чтобы лишний раз не дергать сервер.

 

// Процедура обрабатывает текст ошибки
//
// Назначение:
//
//     1. Иерархическая обработка ошибок.
//        На каждом уровне иерархии ошибку можно дополнить уточняющими
//        сведениями о месте ее возникновения.
//        Примерамии иерархии являются: вложенный вызовов процедур,
//        вложенные циклы, вложенные условия "Если Тогда Иначе" и т. д.
//
//     2. Гибкость выбора места вывода ошибок.
//        Вопрос: где выводить ошибку, в процедуре, где она возникла,
//        или в вызывающей процедуре решается гибко.
//        Если внешнюю процедуру ошибка интересует, то ошибка будет передана ей,
//        иначе вывод ошибки будет сделан во внутренней процедуре.
//
//     3. Накопление списка ошибок и выдачи их единым результатом,
//
//
//
// Параметры
//
//     ТекстНакопительОшибок - либо Неопределено, либо строка. Входной и выходной параметр.
//                             Текст, содержащий список ошибок
//     ТекстОшибки           - строка, входной параметр.
//                             Текст ошибки или собранный ранее накопитель ошибок
//     КоординатыОшибки      - любой тип, входной параметр.
//                             Приводится к строковому типу. Текст информирующий пользователя
//                             о месте возникновения ошибки. Следует указать место в
//                             именительном падеже, например "Строка 1" или ЭтотОбъект.Ссылка
//
//
// Описание
//
// 1. Если ТекстНакопительОшибок - имеет тип "Строка", то ТекстОшибки и КоординатыОшибки
//    будут добавлены в ТекстНакопительОшибок, при этом, вывода на экран не будет
//
// 2. В противном случае ТекстОшибки и КоординатыОшибки будут выведены на экран
//
// Замечание 1. Повторные одинаковые ошибки накопитель отбрасывает
// Замечание 2. Если ТекстОшибки - не простая ошибка, а уже ранее собранный накопитель
//              ошибок, то КоординатыОшибки будут добавлены слева к уже существующим
//              координатам каждой из ошибок
//
//
//
// Пример.
//
//
//      Процедура ОбработатьСтроку(НомерСтроки, Ошибки = Неопределено)
//          ОшибкуОтдать(Ошибки, "Лимит превышен", "Строка " + НомерСтроки);
//      КонецПроцедуры
//
//
//      Процедура ВариантСУточнением(Ошибки = Неопределено)
//          Ош = "";
//          ОбработатьСтроку(1, Ош);
//          ОбработатьСтроку(2, Ош);
//          Если ЗначениеЗаполнено(Ош) Тогда
//              ОшибкуОтдать(Ошибки, Ош, "ТЧ Данные");  // отдаем ошибку нижнего уровня наверх,
//                                                      // уточняя своими координатами
//          КонецЕсли;
//      КонецПроцедуры
//
//
//      Процедура ВариантБезУточнения(Ошибки = Неопределено)
//          ОбработатьСтроку(1, Ошибки);             // Проносим ошибку без контроля
//          ОбработатьСтроку(2, Ошибки);             //
//      КонецПроцедуры
//
//
//      Процедура Испытание()
//          ВариантСУточнением();                    // выдаст:
//                                                   //     Лимит превышен. См. ТЧ Данные, Строка 1
//                                                   //     Лимит превышен. См. ТЧ Данные, Строка 2
//
//          Ошибки = "";
//          ВариантСУточнением(Ошибки);
//          Если Ошибки <> "" Тогда
//              ОшибкуОтдать(, Ошибки, "Испытание"); // выдаст:
//                                                   //     Лимит превышен. См. Испытание, ТЧ Данные, Строка 1
//                                                   //     Лимит превышен. См. Испытание, ТЧ Данные, Строка 2
//          КонецЕсли;
//
//
//
//          ВариантБезУточнения();                   // выдаст:
//                                                   //     Лимит превышен. См. Строка 1
//                                                   //     Лимит превышен. См. Строка 2
//
//          Ошибки = "";
//          ВариантБезУточнения(Ошибки);
//          Если Ошибки <> "" Тогда
//              ОшибкуОтдать(, Ошибки, "Испытание"); // выдаст:
//                                                   //     Лимит превышен. См. Испытание, Строка 1
//                                                   //     Лимит превышен. См. Испытание, Строка 2
//          КонецЕсли;
//      КонецПроцедуры
//
//

Процедура ОшибкуОтдать(ТекстНакопительОшибок = Неопределено, ТекстОшибки = "", КоординатыОшибки = Неопределено) Экспорт

    Если не
ЗначениеЗаполнено(ТекстОшибки) Тогда
        Если не
ЗначениеЗаполнено(ТекстНакопительОшибок) или не ЗначениеЗаполнено(КоординатыОшибки) Тогда
            Возврат;
        КонецЕсли;
    КонецЕсли;

   
РазделительСписка = "..|..";    // между ошибками
   
Сцепка = ":,:";                 // между текстом ошибки и координатами


    // Возможно пользователь использовал Символы.ПС в своих нуждах, поэтому
    // временно заменим все Символы.ПС на другую комбинацию символов.
    // Потом вернем назад

   
ВместоПС = "{;}";                 // временно заменяет Символы.ПС



   
ТекстНак = СтрЗаменить(СокрЛП(ТекстНакопительОшибок), Символы.ПС, ВместоПС);
   
ТекстНак = СтрЗаменить(ТекстНак, РазделительСписка, Символы.ПС);

   
ТекстТек = СтрЗаменить(СокрЛП(ТекстОшибки), Символы.ПС, ВместоПС);
   
ТекстТек = СтрЗаменить(ТекстТек, РазделительСписка, Символы.ПС);

   
Коорд    = СокрЛП(КоординатыОшибки);


   
// Разложение параметра ТекстНакопительОшибок в массив строк
   
мвОшибки = Новый Массив;
    Для
к = 1 По СтрЧислоСтрок(ТекстНак) Цикл
       
мвОшибки.Добавить(СтрПолучитьСтроку(ТекстНак, к));
    КонецЦикла;


   
// Разложение параметра ТекстОшибки на строки и их добавление в массив строк
   
Для НомерСтроки = 1 По СтрЧислоСтрок(ТекстТек) Цикл

       
ТекстСтроки = СокрЛП(СтрПолучитьСтроку(ТекстТек, НомерСтроки));
       
КоордСтроки = "";


       
к = Найти(ТекстСтроки, Сцепка);
        Если
к > 0 Тогда
           
КоордСтроки = СокрЛП(Сред(ТекстСтроки, к + СтрДлина(Сцепка)));
           
ТекстСтроки = СокрЛП(Лев(ТекстСтроки, к-1));
        КонецЕсли;


        Если
Коорд <> "" Тогда
            Если
КоордСтроки = "" Тогда
               
КоордСтроки = Коорд;
            Иначе
               
КоордСтроки = Коорд + ", " + КоордСтроки;
            КонецЕсли;
        КонецЕсли;


        Если
КоордСтроки <> "" Тогда
           
ТекстСтроки = ТекстСтроки + Сцепка + КоордСтроки;
        КонецЕсли;


        Если
мвОшибки.Найти(ТекстСтроки) = Неопределено Тогда
           
мвОшибки.Добавить(ТекстСтроки);
           
ТекстНак = ТекстНак + ?(ТекстНак = "", "", Символы.ПС) + ТекстСтроки;
        КонецЕсли;

    КонецЦикла;




    Если
ТипЗнч(ТекстНакопительОшибок) = Тип("Строка") Тогда

       
ТекстНак = СтрЗаменить(ТекстНак, Символы.ПС, РазделительСписка);
       
ТекстНак = СтрЗаменить(ТекстНак, ВместоПС, Символы.ПС);

       
ТекстНакопительОшибок = ТекстНак;

    Иначе

       
ТекстНак = "";
        Для каждого
ТекстСтроки Из мвОшибки Цикл
           
ТекстСтр = ТекстСтроки;
            Если
СтрДлина(ТекстСтр) > 100 Тогда
               
ТекстСтр = СтрЗаменить(ТекстСтр, Сцепка, ВместоПС + "См. ");
            Иначе
               
ТекстСтр = СтрЗаменить(ТекстСтр, Сцепка, ". См. ");
            КонецЕсли;
           
ТекстНак = ТекстНак + ?(ТекстНак = "", "", РазделительСписка) + ТекстСтр;
        КонецЦикла;

       
ТекстНак = СтрЗаменить(ТекстНак, РазделительСписка, Символы.ПС); // каждую ошибку с новой строки
       
ТекстНак = СтрЗаменить(ТекстНак, ВместоПС, Символы.ПС);          // обратная замена

       
Сообщение = Новый СообщениеПользователю;
       
Сообщение.Текст = ТекстНак;
       
Сообщение.Сообщить();

    КонецЕсли;


КонецПроцедуры

Вступайте в нашу телеграмм-группу Инфостарт

См. также

Тестирование QA DevOps и автоматизация разработки Программист Пользователь 1С v8.3 1С:Бухгалтерия 3.0 Россия Бухгалтерский учет Налоговый учет Платные (руб)

Автотесты 1С - готовые тестовые сценарии, предназначенные для регресс-тестирования функционала конфигурации после обновления типовым релизом. Сценарии проверяют интерактивное заполнение форм документов, справочников и результат проведения документов. Сценарий – feature-файл, разработанный с помощью vanessa-automation. Запуск сценария выполняется интерактивно с помощью vanessa-automation или с помощью vanessa-runner в CI-системах. Доступно тестирование тонкого клиента. Поддерживаемые версии конфигураций 1С:Бухгалтерия предприятие 3.0 и версии КОРП: 3.0.178.26.

2160 руб.

20.01.2022    9677    36    0    

18

DevOps и автоматизация разработки Тестирование QA Программист Пользователь 1С v8.3 1С:Зарплата и Управление Персоналом 3.x Россия Бухгалтерский учет Платные (руб)

Автотесты 1С - готовые тестовые сценарии, предназначенные для регресс-тестирования функционала конфигурации после обновления типовым релизом. Сценарии проверяют интерактивное заполнение форм документов, справочников и результат проведения документов. Сценарий – feature-файл, разработанный с помощью vanessa-automation. Запуск сценария выполняется интерактивно с помощью vanessa-automation или с помощью vanessa-runner в CI-системах. Доступно тестирование тонкого клиента. Поддерживаемые версии конфигураций 1С:Зарплата и Управление Персоналом 3 и версии КОРП: 3.1.30.230.

3360 руб.

05.08.2024    2939    18    1    

12

Тестирование QA Бесплатно (free)

В статье расскажем, как Sentry помогает компании Magnit Tech эффективно решать задачи оперативного выявления и анализа ошибок. Поделимся практическим опытом внедрения Sentry и объясним, почему этот инструмент превосходит другие бесплатные аналоги по функционалу и удобству использования. Рассмотрим гибкий механизм настройки оповещений об ошибках журнала регистрации, который позволяет адаптировать уведомления под конкретные нужды проектов. Объясним, как Sentry используется для мониторинга производительности базы 1С, обеспечивая стабильность работы критически важных систем. Затронем тему интеграции Sentry с системами мониторинга инфраструктуры и CDN.

17.07.2025    765    daniloffartur    1    

5

Тестирование QA Бесплатно (free)

YAxUnit – это сравнительно молодой, но амбициозный и быстро развивающийся инструмент из мира open-source. Расскажем о ключевых этапах развития инструмента и особенностях работы над open-source проектом.

17.07.2025    1920    Жолтокнижниг    1    

18

HighLoad оптимизация Тестирование QA Системный администратор Программист Бесплатно (free)

В мире 1С импортозамещение используемых программных продуктов в первую очередь касается миграции СУБД с MSSQL на Postgres. Одна из основных проблем перехода — более «слабый» оптимизатор запросов Postgres по сравнению с MSSQL, когда запросы на MSSQL выполнялись значительно быстрее, чем на Postgres. Автор статьи разработал инструмент, который позволяет без значительных затрат выявить эти «проблемные» запросы. Основная идея подхода: конвертация на Postgres запросов, снятых при использовании MSSQL, и сравнение времени выполнения на MSSQL и на Postgres.

10.07.2025    1324    berserg    4    

7

Тестирование QA Программист Бесплатно (free)

Процесс тестирования в команде автора эволюционировал от ручных проверок до полноценной автоматизации с использованием современных инструментов и контейнеризации. Начав с Vanessa-ADD в качестве основного решения, команда постепенно расширила стек, включив в него Vanessa-Automation для UI-тестирования, YAxUnit для модульных проверок, Coverage41C для анализа покрытия кода, а также Gitlab CI, Allure и SonarQube для мониторинга качества и непрерывной интеграции. Статья объясняет, почему в качестве стартового инструмента была выбрана Vanessa-ADD и как удалось организовать запуск дымовых и сценарных тестов в CI-контуре на Windows-сервере. Рассмотрен вопрос анализа покрытия кода тестами: зачем потребовался подсчет и какими сложности сопровождали настройку Coverage41C в клиент-серверной архитектуре. Также автор рассказывает про переход на Docker (рассматривался готовый образ, но в итоге был создан собственный) и смену инфраструктуры с Windows и PowerShell на Linux и Bash.

27.06.2025    2065    TaGolovkina    3    

21

Тестирование QA Бесплатно (free)

Ведущий разработчик Инфостарт Лаборатории рассказал о том, с какими сложностями сталкиваются команды разработки 1С, внедряющие у себя процессы автоматизации тестирования и о подходах и конкретных решениях, которые помогают эти проблемы обойти. Доклад прозвучал на конференции «Стачка» в Ульяновске в апреле 2025 года и был ориентирован на руководителей и тимлидов команд разработки и тестирования, а также на действующих тестировщиков.

20.06.2025    4125    kuntashov    5    

38

WEB-интеграция Тестирование QA Программист 1С v8.3 1С:Библиотека стандартных подсистем Абонемент ($m)

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

1 стартмани

12.05.2025    856    1    serg-lom89    3    

6
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. maxx 999 29.09.13 19:55 Сейчас в теме
Идея хорошая, я бы еще добавил в объект СообщениюПользователя путь к данным объектов или мест где возникла ошибка, чтобы навигация работала по списку ошибок, т.е нажал по ошибке и перешел сразу к месту где ошибка
2. Abadonna 3972 30.09.13 04:34 Сейчас в теме
(0)
// Возможно пользователь использовал Символы.ПС в своих нуждах, поэтому
// временно заменим все Символы.ПС на другую комбинацию символов.
// Потом вернем назад

ВместоПС = "{;}";

Рекомендую: (ALT+0134) (ALT+0135) - никогда простой юзверь такое на клавиатуре не наберет ;)
CratosX; rkravtsov; +2 Ответить
3. Yashazz 4861 30.09.13 12:45 Сейчас в теме
Да, уже витает в воздухе.
Я себе смастерил накопитель в виде дерева, которое отслеживает "погружение" в вызовы различных процедур да функций; а потом вывожу его в макет с расшифровкой, и показываю, где были какие сообщения. Красиво и удобно, но кода требует, конечно.
4. ufo58 161 30.09.13 17:12 Сейчас в теме
все бы ничего
и идея хороша, и посыл нормальный
но ... выводить "Сообщением", тем более в управляемых формах ... бррр
да и Дерево ... тяжеловато
подумай, может дать вариант формирования тип Текст ?
с последующим просмотром
или сохранением ...
5. TitanLuchs 522 02.10.13 14:42 Сейчас в теме
Присоединюсь к предыдущему оратору. При возможности тоже стараюсь избегать использование "Сообщить" и "СообщениеПользователю" в УФ, потому что перекореживание формы в этот момент - это иногда зрелище не для слабонервных. Одно время в своей конфе открывал отдельное окно с сообщениями, на быстродействии это не сказывалось (потому что форма все равно перерисовывается при изменении размера), но юзеров не так бесило.
6. pakill 43 03.10.13 09:38 Сейчас в теме
Вообще-то я старался сделать легкую процедуру, не зависящую ни от конфигурации, ни от контекста.
Писать что-то тяжеловесное на тот случай, который может никогда и не произойти как-то не хотелось. Я лишь ставил цель, предоставить пользователю шанс самостоятельно разобраться и исправить ошибку в данных, если таковая возникнет.

Насчет вывода ошибки с помощью Сообщить():
А как ее еще выводить на стороне сервера?

Это можно сгладить лишь частично:

#Если Сервер Тогда
Сообщить(...);
#Иначе
Предупреждение(...);
#КонецЕсли

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

7. Yashazz 4861 03.10.13 12:57 Сейчас в теме
(6) Вот я именно и заменил "Сообщить" своей процедурой. И УФ не корёжит, и на сервере работает, в протокол пишет.
8. devel0per 1 08.10.13 02:08 Сейчас в теме
Хоть комментарий к процедуре и прекрасен, но из него не ясно чем плох отладчик, ведь
нам никто не запрещает им пользоваться на сервере.
Не лучше ли будет вместо:
Коорд    = СокрЛП(КоординатыОшибки);

и
Если Коорд <> "" Тогда

писать:
Если ПустаяСтрока(Коорд) Тогда

Вот не помню в клюшках функц. ПустаяСтрока была?
14. pakill 43 09.10.13 02:44 Сейчас в теме
(8). Чем же плох отладчик? Чтож. Дайте пользователю отладчик. Пусть ищет и исправляет ошибки в данных (подчеркиваю в данных, а не в коде). Ну а я, как-то не готов давать пользователю отладчик.

Коорд = СокрЛП(..) // это чтобы вместо: "текст , текст" всегда было так: "текст, текст"
Если Коорд <> "" Тогда

Здесь первая строка нужна сама по себе, а не для того, чтобы выполнить проверку во второй строке.
Но поскольку она все же есть, то не вижу ничего плохого чтобы сравнить <> ""


(12). Насчет Попытка-Исключение.
А Вы попробуйте воспроизвести в точности тот пример из комментария с помощью попытки-исключения.
И сразу же выяснится, что вы будете заниматься разбором строк в каждой процедуре, где используете эту конструкцию. Кроме того, у Вас возникнут трудности при передаче списка ошибок. И чтобы облегчить жизнь придется написать свою процедуру, занимающуюся разбором строк и накоплением ошибок.
Но скорее всего, Вы просто используете ту самую процедуру ОшибкуОтдать(), приведенную выше.
Так что, попытка-исключение - это всего лишь, один из способов ее применения.


>>
Ну а исключение клиентского (самого высокого) уровня уже можно как угодно отработать. Сообщением, предупреждением, или записью в лог.


Заметьте, принципиальную разницу: сообщение может быть выдано не только на верхнем уровне, а на любом из уровней. В примерах как раз показан вывод из разных процедур. И это зависит от того, как вызвана процедура.
В Вашем случае - это наличие или отсутствие конструкции попытка-исключение в процедурах верхнего уровня.
Это значит, что "ВызватьИсключение" - это и есть Ваш способ вывода ошибки, т.е. Вы с этим уже заранее определились.
9. WalterMort 247 08.10.13 13:49 Сейчас в теме
Автор изобрел велосипед, вместо грамотной работы с исключениями.
10. Evil Beaver 8357 08.10.13 13:56 Сейчас в теме
(9) WalterMort, ну тогда уж приводите пример "грамотной" работы с исключениями в рамках поставленной задачи. Что вы понимаете под "грамотной" работой?
12. WalterMort 247 08.10.13 14:55 Сейчас в теме
(10) Обычная передача ошибок снизу наверх. Классов исключений в 1С нет, но описания ошибки для замысла автора достаточно:

Процедура Внешняя()
Попытка
Внутренняя();
Исключение
ВызватьИсключение "Невозможно выполнить внешняя: " + ОписаниеОшибки(); // наверх
КонецПопытки;
КонецПроцедуры

Процедура Внутренняя()
Попытка
а = б/0;
Исключение
ВызватьИсключение "Невозможно выполнить внутренняя"; // передаем наверх
КонецПопытки;
КонецПроцедуры


Результат: "Невозможно выполнить внешняя: Невозможно выполнить внутренняя"



Ну а исключение клиентского (самого высокого) уровня уже можно как угодно отработать. Сообщением, предупреждением, или записью в лог.
13. Evil Beaver 8357 08.10.13 16:05 Сейчас в теме
(12) WalterMort, вот поскольку классов исключений нет, то все, что могут передать исключения - это строки. Отсюда, шибко "грамотной" работы с исключениями все равно не будет.
11. Bukaska 148 08.10.13 13:56 Сейчас в теме
(9) WalterMort, Ой да ладно.. ну что же вы все как эти... даже не знаешь как назвать... Я конечно понимаю что нужно реализовываться, знаю что и инициатива бывает наказуема. Но кто не работает, тот не ест)))
15. monkbest 114 27.05.16 09:10 Сейчас в теме
Оставьте свое сообщение