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

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 Тогда
               
ТекстСтр = СтрЗаменить(ТекстСтр, Сцепка, ВместоПС + "См. ");
            Иначе
               
ТекстСтр = СтрЗаменить(ТекстСтр, Сцепка, ". См. ");
            КонецЕсли;
           
ТекстНак = ТекстНак + ?(ТекстНак = "", "", РазделительСписка) + ТекстСтр;
        КонецЦикла;

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

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

    КонецЕсли;


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

См. также

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

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

2160 руб.

05.08.2024    1278    12    1    

7

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

Готовые тестовые сценарии, предназначенные для регресс-тестирования функционала конфигурации после обновления типовым релизом. Сценарии проверяют интерактивное заполнение форм документов, справочников и результат проведения документов. Сценарии возможно использовать как для vanessa-automation, так и для СППР. Поддерживаемые версии конфигураций ERP2 и КА2: 2.5.17.113.

2400 руб.

04.07.2022    8368    38    1    

29

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

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

1800 руб.

20.01.2022    7783    19    0    

13

Облачные сервисы, хостинг Linux Тестирование QA Сервера Системный администратор Программист Платформа 1С v8.3 Бесплатно (free)

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

31.10.2024    1308    capitan    0    

0

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

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

21.10.2024    2782    leemuar    8    

22

Тестирование QA Системный администратор Программист Платформа 1С v8.3 Бесплатно (free)

Пишете много тестов – хорошо. Покрытие достаточно высокое – отлично. Но баги все равно попадаются – плохо. Раз юниты и фича-файлы – это код, значит, их можно протестировать. Расскажем о подходе «мутационное тестирование», позволяющем оценить надежность тестов и повысить к ним доверие.

30.08.2024    1292    Scorpion4eg    6    

7

Тестирование QA Программист Платформа 1С v8.3 Бесплатно (free)

Иногда возникают ситуации, когда надо развернуть тестовую базу клиента / свою на серверах Windows или Linux. Тестовые базы могут понадобиться в разных ситуациях: у клиента ошибка, на нашей базе она не воспроизводится, реализуем новый функционал и хотелось бы протестировать на Linux и т.д. А теперь представим, что это все на потоке. Что тестовых баз 1С не одна, а 20-30. И получаем проблему, что непонятно, занята она сейчас кем-то или нет. Предлагаю вариант решения этой проблемы.

28.06.2024    1511    Diversus    12    

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

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

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

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

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

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

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

7. Yashazz 4790 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 246 08.10.13 13:49 Сейчас в теме
Автор изобрел велосипед, вместо грамотной работы с исключениями.
10. Evil Beaver 8243 08.10.13 13:56 Сейчас в теме
(9) WalterMort, ну тогда уж приводите пример "грамотной" работы с исключениями в рамках поставленной задачи. Что вы понимаете под "грамотной" работой?
12. WalterMort 246 08.10.13 14:55 Сейчас в теме
(10) Обычная передача ошибок снизу наверх. Классов исключений в 1С нет, но описания ошибки для замысла автора достаточно:

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

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


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



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