Сводка

Текущая версия 1.3.4.4 История релизов
Последние обновления

https://github.com/grumagargler/tester

Депо общих тестов

https://github.com/grumagargler/CommonTests

Депо демо тестов для ERP2 (демо)

https://github.com/grumagargler/ERP2

Сайт проекта

http://www.test1c.com

Разработчик Решитко Дмитрий
Поддержка

https://gitter.im/tester1c/Lobby

grumagargler@gmail.com

Стоимость / Лицензия Бесплатно / BSD (в модуле управляемого приложения)
Язык

Интерфейс: Английский, Русский

Справка: Английский (частично), Русский

Содержание

Вступление

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

Во многом, эти вопросы решаются внедрением специальных методик, например, TDD, BDD, организацией дополнительных процессов по тестированию. Однако, везде есть свои нюансы.

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

BDD, за счет человеческого языка сценариев Gherkin, идеологически сшивает в одном месте специалистов прикладной и технической областей, а используемая конструкция описания сценариев Given-When-Then универсальна. Однако, BDD больше о процессе создания продукта, а не только о его тестировании. BDD основывается на ролевом взаимодействии сотрудников компании, что делает её требовательной (и в какой-то мере хрупкой) ко всем звеньям цепи разработки. Другой важной проблемой является не высокая эффективность языка Gherkin при разработке сложных (с точки зрения BDD) сценариев. К автоматическому документированию, как бонусу BDD, также, немало вопросов. Руководства пользователя к продуктам известных вендоров, не строятся по принципу Given – When – Then, а с техническим документированием, многие выбирают подход “Лучше устаревшая, но понятная, чем актуальная, но непонятная (или понятная только автору сценариев) документация.

Исторически, TDD, BDD и другие, пришли из мира, где системы 1С нет как класса, где идет очень четкая специализация, и разрыв между понимаем задачи техническим специалистом и бизнесом, как правило, велик. Например, в типовой 1С-франчайзи, очень часто задачи идут конвейером, могут приниматься по телефону, скайпу или электронной почте. Организация заседаний на каждую доработку в формате трех друзей (Three Amigos), выглядит несерьёзно, а значит почти вся методика BDD искажается или даже ломается.

В тоже время, на крупных проектах, эти переговоры необходимы. В идеале там будет аналитик, тестировщик и разработчик (BA+QA+Developer), но там не будет всего отдела программистов. А им, в конечном итоге, писать код, проводить тестирование, зачастую, намного более глубокое, с пограничными значениями, отклонениями, и другими особенностями реализации, возникновение которых рождается в коде и не может быть описано в приемочном тесте или постановке задачи. И это будет не TDD, а реальные сценарные тесты, которые программисты как правило не автоматизируют, а выполняют вручную в рамках процесса кодирования.

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

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

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

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

Базовые определения

Процесс тестирования приложений при помощи Тестера основывается на взаимодействии Тестера с запущенной конфигурацией 1С в режиме 1С:Предприятие.

При этом считается, что Тестер выступает в роли Менеджера тестирования, а тестируемая конфигурация – в роли Клиент тестирования.

Тестер является системой сценарного тестирования. Это означает, что взаимодействие с тестируемым приложением происходит в режиме эмуляции действий пользователя.

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

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

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

Тестер не является системой TDD, и строго говоря, не является идеологически чистым BDD. Тестер старается не привязываться к религии в разработке, он решает те проблемы, с которыми сталкиваются абсолютно все разработчики программного обеспечения. Тестер старается решать эти задачи максимально эффективно.

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

Предполагаемые пользователи Тестера, это:

Пользователи Задачи
Программисты Использование системы в процессе разработки. Эволюция процесса ручного тестирования
Тестировщики с базовыми знаниями программирования на языке 1С Написание сценариев, максимально приближенных к сценариям работы пользователей. Эти сценарии, обычно не такие глубокие, как у программистов, но более выраженные с точки зрения бизнес-процесса
Бизнес аналитики. Консультанты Запуск тестов, анализ результатов. Через чтение тестов, понимание работы функционала системы

Концепция

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

Имея на входе информацию по задаче, мы мысленно разбиваем весь процесс кодирования на небольшие транзакции, рывки. Это является для нас неким краткосрочным планом работ (даже если на входе BDD-сценарий). Затем, мы начинаем методично работать по схеме “написание кода – запуск приложения – проверка ожидаемого поведения – возврат к доработке кода”. Количество таких транзакций и степень их завершенности - очень хрупкие сущности, потому что опираются на способность и возможность программиста быть в сосредоточении.

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

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

Интегрирование в работу инструмента тестирования, потребует от программиста выработки навыка трансляции мысленно составленного плана работ в программный код сценария. Это дает ему возможность “разгружаться” сериализуясь в код теста. Накапливаемые сценарии, всегда можно воспроизвести, что позволяет сосредоточится на качестве выполняемых работ. Рост количества тестов дает свободу действий не только для рефакторинга, но и других существенных изменениях функциональности разрабатываемого приложения, что является одной из важных концепций инструмента.

Быстрый старт

Развертывание

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

  1. Конфигурация Тестер должна быть запущена в режиме 1С:Предприятие с ключом /TESTMANAGER.
    Этот параметр может быть прописан непосредственно в профиле информационной базы Тестера, например так:

     
  2. Тестируемая конфигурация должна быть запущена в режиме 1С:Предприятие с ключом /TESTCLIENT.
    Этот параметр может быть прописан непосредственно в профиле тестируемой информационной базы, например так:
  3. Версия 1С, используемая для тестирования должна быть одинаковой как для Тестера, так и для тестируемой конфигурации.
  4. Запуск Тестера и тестируемой конфигурации желательно производить на одном компьютере. Для запуска программ на разных компьютерах, необходимо настроить порт и адрес тестируемого приложения в справочнике Приложения.

С технической точки зрения, для начала разработки тестов и тестирования больше ничего не требуется.

Первый сценарий

Рассмотрим пример создания теста к конфигурации БСП 2.2.

Напишем элементарный тест, который просто откроет форму списка справочника Партнеры.

  1. Запускаем Тестер с ключом /TESTMANAGER.
  2. Запускаем БСП с ключом /TESTCLIENT.
  3. Переключается в Тестер, открываем меню быстрых функций и создаем новое приложение:

  4. Через меню быстрых функций открываем сценарии и создадим новый сценарий:
    1. В поле ID напишем Test1
    2. В тексте сценария напишем:
    3. Подключить (); // Подключаем БСП к Тестеру
      Меню ( "Справочники / Демо: Партнеры" ); // Открываем в БСП форму списка
    4. Переключимся на вкладку Свойства, и в поле Приложение укажем БСП
    5. Нажмем на панели кнопку Основной
    6. Тест готов. Теперь нажмем кнопку Запустить (или F5) и запустим его.

В результате, в БСП должна открыться форма списка справочника Демо: Партнеры. Если бы во время открытия справочника, произошла какая-то ошибка, Тестер бы о ней сообщил.

Второй сценарий

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

// Подключаем БСП к Тестеру
Подключить ();

// Закроем все окна в БСП
ЗакрытьВсё ();

// Открываем в БСП форму списка
Меню ( "Справочники / Демо: Партнеры" );

// Говорим Тестеру, что мы будем сейчас работать с этим окном
Здесь ( "Демо: Партнеры" );

// Нажмем кнопку Создать
Нажать ( "Создать" );

// Говорим Тестеру, что мы будем сейчас работать с этим окном
Здесь ( "Демо: Партнер (создание)" );

// Установим наименование партнера
Установить ( "Наименование", "Мой тестовый партнер" );

// Кликнем на флажок Поставщик
Нажать ( "Поставщик" );

// Нажмем кнопку Записать и закрыть
Нажать ( "Записать и закрыть" );

После выполнения теста, в базе БСП должен быть новый партнер.

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

14: Поле "Создать" найдено в нескольких местах: ФормаСоздать (Тестируемая кнопка формы / Кнопка командной панели), СписокКонтекстноеМенюСоздать (Тестируемая кнопка формы / Кнопка командной панели) {Тест1[14]}

Сообщение говорит о том, что в 14 строке кода, метод Нажать нашел несколько мест, где можно нажать Создать.

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

Например, в 14 строке можно написать так:

// Вариант 1
Нажать ( "!ФормаСоздать" );

// Вариант 2
Нажать ( "!КоманднаяПанель / Создать" );

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

Следующие разделы посвящены полному обзору функций Тестера.

Интерфейс

Интерфейс Тестера организован с позиций удобного написания и запуска тестов. При первом запуске, на домашнюю страницу выводится справка по системе (выкачивается из интернета) и открывается основной сценарий, если он задан. В левой части системы находится текстовый редактор для ввода кода сценария, справа – дерево сценариев.

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

Дерево сценариев

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

Когда вы запускаете Тестер, в правой части экрана находится дерево сценариев. Это дерево позволяет организовать сценарии в виде иерархии. Каждый узел дерева имеет тип. Тип задает смысловое значение сценариев внутри узла, сортировку и пиктограмму. В терминологии 1С, это дерево – обычный иерархический справочник.

На картинке ниже показан пример дерева тестов из демонстрационной базы, и далее дано описание каждого маркера:

Типы сценариев, Маркер 1

Левее маркера, в зеленом цвете и специальной пиктограмме, находятся такие узлы как Корзина, Общее, Таблица и другие.

Такое оформление означает, что это библиотеки тестов. Признак, что узел является библиотекой, задается при создании/редактировании теста:

На картинке видно, что кроме библиотеки, тест может быть папкой, сценарием или методом.

Строгой технической привязки и контроля типа сценария в Тестере нет. Главное предназначение типов – это организация визуальной логики взаимосвязи сценариев.

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

Пример метода: ПроверитьОшибкуЗаписи.

Пример использования в коде сценария:

Вызвать ( "Общее.ПроверитьОшибкуЗаписи", "Не заполнен контрагент" );

Группы сценариев, Маркер 2

На этом маркере изображена папка Документы. Папка – это логическая группировка сценариев. Группировка может быть произвольной. Вы можете создавать папки с тестами по принципу тестируемых подсистем, ролей пользователей или технических заданий. Если вы не чувствуете, какая структура тестов вам нужна, тогда универсальным подходом является проецирование структуры тестов на объекты метаданных вашей конфигурации. Смело можно создавать группы Справочники, Документы и так далее. Внутри этих групп, создавать группы с названиями объектов метаданных, а следующим уровнем, располагать конкретные сценарии. В будущем, если потребуется, вы сможете сделать перегруппировку.

Обычный сценарий, Маркер 3

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

Сценарий-метод, Маркер 4

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

Основной сценарий, Маркер 5

Этим маркером отмечен обычный сценарий. Подчеркивание снизу указывает на то, что данный сценарий в настоящий момент текущий (основной). Основной сценарий, это тот сценарий, над которым сейчас работает программист. Любой сценарий может быть установлен основным (правый клик в дереве / Основной). У каждого пользователя системы Тестер может быть свой основной сценарий. Основной сценарий отличается от остальных тем, что его легко найти в дереве (правый клик в дереве / Найти основной сценарий) и легко запустить на выполнение (см. Запуск тестов). Также, основной сценарий автоматически открывается при запуске новой сессии Тестера.

Приложения, Маркер 6

Под маркером 6 находится колонка с названием приложения, к которому принадлежит соответствующий сценарий.

Приложение устанавливается в форме редактирования сценария, для любого типа сценария:

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

Обратите внимание, что для библиотечных тестов и групп первого уровня (см. картинку с деревом тестов) приложение не задано, а для группы ЗаказПоставщику, ТестСоздания и т.д. приложение задано. Логика следующая: библиотечные тесты могут работать для любой конфигурации, поэтому при их создании, приложение не задали. Группа тестов Документы тоже будет в любой конфигурации, приложение также не задано. Для группы ЗаказПоставщику, ТестСоздания и т.д. приложение задано, потому что они имеет четкую привязку к тестируемому приложению.

Задавать приложение для сценариев нужно:

  1. Для логической группировки сценариев и возможности отбора сценариев в дереве тестов, см. картинку:
  2. Для контроля уникальности имен сценариев. Например, может существовать несколько тестов с названием ЗаказПоставщику, если для каждого из них задано отдельное приложение. Создать еще одну группу тестов с названием Документы нельзя, потому что она задана как общая, без указания конкретного приложения.

Хранилище, Маркер 7

Правее маркера, находится колонка, определяющая в виде пиктограммы статус сценариев в хранилище тестов.

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

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

При помещении изменений в хранилище, ваши изменения становятся доступны всем пользователям. Если вы разрабатываете определенный функционал, и ваши изменения теста могут затронуть работоспособность других связанных тестов, рекомендуется использовать метод МояВерсия ().

Запуск тестов

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

Основной способ запуска тестов это кнопка F5 или команда Запустить:

При запуске теста по кнопке F5 (или командe Запустить) Тестер всегда запускает сценарий, установленный как основной. Таким образом, вне зависимости от кого, какой сценарий вы в данный момент редактируете, запускаться будет только основной.

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

Вкладка Поля

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

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

Для такой задачи на форме сценария присутствует вкладка Поля (для новых сценариев, вкладка скрыта, сценарий должен существовать):

По порядку следования маркеров:

  1. Позволяет получить структуру всех окон тестируемого приложения, которые сейчас открыты на экране.
  2. Позволяет получить только текущее окно тестируемого приложения.
  3. Позволяет быстро найти в дереве элементов текущий активный элемент тестируемого приложения. Очень удобная функция при написании тестов. Например, можно открыть нужную форму и встать на нужный элемент, затем, в Тестере, получить эту форму (п.2) и нажать Синхронизировать. После этого, Тестер попытается найти и активировать строку в дереве с данным элементом. В случае неудачи, генерируется ошибка.
  4. При навигации по дереву, Тестер пытается активировать выделенные элементы в тестируемом приложении. Будьте внимательны, фокус может “прыгать” с дерева на тестируемое приложение.
  5. Для выделенного поля можно выполнить метод или получить свойство. Набор методов и свойств зависит от типа выделенного элемента и применяется согласно объектной модели тестируемого приложения платформы 1С. Например, на картинке поле ОтборСостояние имеет тип ТестируемоеПолеФормы. В синтаксис помощнике 1С, можно посмотреть, какие методы и свойства доступны объектам этого типа. Одно из них, свойство ТекстЗаголовка, результат получения которого выведен на картинке выше.

Внедрение

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

Перед погружением в детали, определимся с тем, когда автоматизированное тестирование применять неэффективно:

  1. Вы создаете макет, прототип приложения для демонстрации заказчику
  2. Вы вносите точечные исправления в старый код, в те механизмы, сценариев к которым нет и не будет, и вся эта работа без перспектив эволюции модулей
  3. Вы прощупываете будущую реализацию, когда еще нет четкого понимания, что это должно быть, документ или справочник, отчет или динамический список. В этом случае, программист нередко переключается в режим “потока” и быстро накидывает объекты метаданных для того, чтобы доказать или опровергнуть самому себе достижимость результата выбранным путем. В таких ситуациях, практически невозможно выработать сценарий, но это и не нужно. Строго говоря, пока не сформируется полное представление о способе выполнения задачи, сценарное тестирование применять не стоит

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

Установка

    Если вы занимаетесь обслуживанием клиентов частным образом, Тестер имеет смысл установить локально на ваш компьютер или ноутбук, файловый вариант.

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

    Даже если ваша команда сильно распределена, с пингом до ~125мс всё еще можно комфортно работать через интернет, разработка Тестера велась с учетом удаленности программистов. Если по каким-то причинам, облачное решение организовать не получается, можно установить программу локально на каждый компьютер специалиста, файловый вариант. Для организации общего хранилища тестов, можно использовать Git. У Тестера есть возможность инкрементальной выгрузки/загрузки тестов в файловую систему.

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

    Тестер позволяет в одной базе вести работу с тестами для неограниченного числа приложений (конфигураций). Не стоит создавать отдельную базу с Тестером под каждый проект/конфигурацию/клиента. В Тестере возможна настройка ограничения доступа пользователей к приложениям.

    Базы данных

    Тестирование при помощи Тестера предполагает наличие двух баз данных: рабочей и начальной.

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

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

    Создание и обновление начальной базы

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

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

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

    Использовать такой тест удобно в следующих случаях:

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

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

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

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

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

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

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

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

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

    Эталонная база

    Эталонная база данных используется для тестирования бизнес-логики приложения.

    Использование эталонной базы при интеграции тестирования в процесс разработки не эффективно и не используется Тестером по следующим причинам:

    1. Требуется особый уход за эталонными данными, их корректировка в соответствии с изменениями функционала решения
    2. Эталонные данные инертны: новый функционал требует новых эталонных данных, которые могут пересекаться с уже существующими эталонными данными. Вытекающая отсюда осторожность при манипуляции с эталонными данными ограничивает или замедляет развитие спектра тестируемого функционала
    3. Оперативный прогон тестов практически невозможен, выгружать/обновлять/загружать эталонные базы долго. Под оперативностью понимается тестирование при каждом запуске программистом приложения на выполнение, а не увеличение числа релизов и закачки схемы на CI-сервере с прогоном тестов в течение дня
    4. Количество эталонных баз стремится расти, это осложняет их обслуживание и весь процесс тестирования

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

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

    Данные для тестирования

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

    Тестовые данные состоят из двух слоёв:

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

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

    1. Выгрузка заготовленных данных из предварительно подготовленных баз или шаблонов, и последующая их загрузка перед началом или во время тестирования. Вариантов выгрузки/загрузки в данном подходе много. Это может быть конвертация данных, универсальный обмен данными, макеты с данными, выгрузки в dt-файлы или обычная сериализация прикладных объектов в JSON или XML.
      Рассмотрим плюсы и минусы такого подхода:

      Плюсы Минусы
      Очевидность подхода Сложность поддержки согласованности данных в развивающемся функционале приложения, проблемы загрузки данных при измененной структуре метаданных, смене владельцев, появлению полей обязательных для заполнения, переименованию или удалению объектов и их реквизитов.
      Быстрый старт в подготовке данных Потенциальная опасность получения не консистентных данных и ложного положительного прохождения теста. Такие тестовые данные как правило загружаются в специальном режиме, без дополнительных проверок и срабатывания обработчиков форм. Фактически, тестовые данные готовятся не так, как это бы сделал пользователь.
        Сложность логистики хранения, взаимосвязанности наборов файлов, данных и тестов.
        Статичность. Данные загружаются как есть и их сложно менять под вариативность тестов в случае необходимости.
        Проблемы с удалением тестовых данных для повторных запусков сценариев.
    2. Формирование тестовых данных самим сценарием. При этом подходе, все тестовые данные должны создаваться, а не храниться для загрузки. Сам процесс создания не должен отличаться от процесса разработки целевых сценарных тестов. Другими словами, сегодня вы пишите тест проверки создания нового товара, а завтра этот тест уже может быть использован как метод для создания тестовых данных, для тестирования создания документа Реализация товаров.
      Плюсы и минусы такого подхода:

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

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

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

      Требуется первоначальная инвестиция времени в разработку тестов-методов
      Консистентность полученного тестового окружения, заполненность реквизитов, отработка возможных событий и программных оповещений об изменении данных, другими словами - полная штатная эмуляция работы приложения.  
      Слабая связанность с изменчивостью структуры метаданных. Если изменяется структура данных объекта, достаточно изменить (если необходимо) один тест-метод, при этом все остальные тестовые данные менять не придётся.  
      Простота хранения. Все тест-методы хранятся в одной среде, и не являются внешними по отношению к системе тестирования.  
      Использование одних и тех же тестовых данных даже в случае, когда их версии метаданных отличаются. В этом случае, в тест-методах можно организовывать условия по обработке/заполнению полей в зависимости от версии используемой программистом конфигурации (см. функцию МояВерсия ())  

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

    Структура сценария

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

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

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

    Чтобы быстро прогонять тесты, нужно чтобы они были следующей структуры:

    1. Определение окружения
    2. Создание окружения
    3. Целевая часть

    Определение окружения – это функция в модуле вашего сценария, которая задает параметры теста в виде структуры. Примеры параметров теста: список приходуемых товаров, с ценами и количеством, наименование поставщика, валюта договора и т.д.

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

    Целевая часть – это непосредственно код, который будет проверять то, что вы запланировали сделать, и ничего более.

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

    Яснее на примере. Давайте представим, что вы занимаетесь доработкой документа Списание ТМЗ, который нужно дополнить особыми движениями по регистрам. Для тестирования (неважно как, вручную или нет) вам понадобится материал на складе, себестоимость которого вы знаете, установленные параметры учетной политики, на которые вы полагаетесь, и другие настройки системы, например, вариант контроля остатков. Таким образом, вам нужно будет вручную, как минимум один раз проверить, что настройки системы в порядке. Затем, нужно будет создать несколько материалов, возможно отдельный склад и как минимум одно поступление ТМЗ, и вы не забудете дату поступления сделать днем ранее. Таким образом – вы определяете и создаете окружение, чтобы затем выполнить целевую часть – провести списание и проверить, что особые движения появились и они правильные. Другими словами – выполняются все три описанных выше структурных действия для разработки автоматизированного сценария.

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

    Пример. Добавим в описанную задачу необходимость проверки сообщения об ошибке при списании количества материала, большего, чем есть на складе. Я сильно не ошибусь, если предскажу работу смекалки программиста: он просто откроет уже проведенное списание (предварительно добавив его в избранное для максимальной “скорости”), отменит его проведение, в колонку с количеством введет 999999, запишет документ, а потом проведет его и проанализирует сообщение об ошибке. Если сообщения не будет, программист вернется в код, сделает необходимые доработки и будет повторять итерацию до тех пор, пока сообщение об ошибке не появится.

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

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

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

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

    Практика

    Перейдем к практической части: поработаем с Тестером в режиме создания нового функционала для конфигурации УТ11 на базе постановки задачи от бизнес-аналитика.

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

    Компания торгует сигарами. Необходимо доработать документ Реализация товаров и услуг (далее Реализация) для возможности указания даты согласования следующих продаж по выбранным позициям. Предполагается следующий сценарий:

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

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

    - Менеджер выбирает нужную позицию из списка, звонит клиенту, и вводит в систему результат переговоров

    Документ Реализация

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

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

    Регистр сведений Согласование

    Это новый, независимый регистр сведений, с возможностью редактирования.

    Регистр должен хранить такие данные:

    1. Документ Реализация, Клиент, Менеджер, Товар, Количество, Сумма – автоматически должны заполняться при проведении реализации и не должны быть доступны для редактирования
    2. Флаг Отработано – будет устанавливаться пользователем
    3. Флаг Комментарий – будет вводиться пользователем и фиксировать результат переговоров. Поле должно быть доступно для редактирования только если флаг Отработано = истина.

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

    Запретить пользователю вводить новые записи в данный регистр интерактивно. Примечание: запрет на ввод нового сделать программно с выводом соответствующего сообщения. Не использовать вместо этого настройку команд и ролей пользователя.

    Объект расположить в подсистеме Продажи / Оптовые продажи.

    Тесты

    Необходимо разработать следующий тест:

    1. Ввод одной реализации с двумя позициями, одна из которых будет отмечена для согласования
    2. Открытие списка на согласование, отбор по клиенту, открытие формы регистра на редактирование, установка галочки, сохранение и закрытие
    3. Убедиться, что позиция ушла из списка

    Примечание: данный тест требуется автором технического задания. Исполнитель (программист) волен разработать столько дополнительных тестов, сколько ему потребуется для обеспечения надлежащего качества выполнения работ.

    Разработка

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

    Можно выделить как минимум четыре этапа:

    Этап 1: добавить реквизит Дата согласования в табличную часть, в процедуре ОбработкаПроверкиЗаполнения реализовать проверку, чтобы дата согласования была больше даты документа

    Этап 2: доработать процедуру ОбработкаПроведения, добавить туда логику формирования записей по регистру сведений

    Этап 3: реализовать форму списка с фильтрами, как требует бизнес-аналитик

    Этап 4: реализовать форму редактирования записи регистра для ввода данных по согласованным позициям.

    Этап 1

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

    Программирование Тестирование

    В Конфигураторе: 

    1. Добавляем реквизит ДатаСогласования в табличную часть Товары документа Реализация
    2. В процедуре ОбработкаПроверкиЗаполнения реализуем проверку даты

    В Тестере:

    Создадим тест ПроверкаДатыСогласования, где:

    1. Введем новую реализацию, добавим строку, впишем в строку некорректную дату
    2. Попытаемся провести, и в списке сообщений найдем требуемое сообщение об ошибке
    3. Затем изменим дату на правильную, проведем и убедимся, что сообщения об ошибке уже нет

    Так как это будет наш первый тест для конфигурации УТ11, нам нужно произвести разовую настройку приложения в Тестере.

    Необходимо создать приложение УТ11, см. Меню функций / Приложения. Для создаваемого приложения нужно задать актуальную на момент написания теста версию, например так:

    Затем, это приложение нужно установить приложением по умолчанию, для этого нужно переключиться в дерево сценариев, открыть Опции, выбрать в поле Приложение УТ11 и нажать кнопку справа:

    Следующий шаг – это создание папки РеализацияТоваровУслуг внутри папки Документы, и следом, создание нашего теста ПроверкаДатыСогласования.

    В итоге, должно получится так:

    Откроем выделенный на картинке сценарий, переключимся в текстовый редактор и введем этот текст:

    // Сценарий:
    // - Вводим новый документ Реализация
    // - Устанавливаем неправильную дату согласования, проверяем наличие ошибки
    // - Устанавливаем правильную дату, проверяем отсутствие ошибки
    
    Подключить ();
    ЗакрытьВсё ();
    
    // Вводим новый документ
    Коммандос ( "e1cib/data/Document.РеализацияТоваровУслуг" );
    Здесь ( "Реализация *" );
    
    // Определяем даты
    дата = Дата ( Взять ( "!Дата" ) );
    плохая = Формат ( дата - 86400, "DLF=D" );
    хорошая = Формат ( дата + 86400, "DLF=D" );
    
    // Вводим плохую дату
    Нажать ( "!ТоварыДобавить" );
    Установить ( "!ТоварыДатаСогласования", плохая );
    
    // Проводим документ
    Нажать ( "!ФормаПровести" );
    если ( НайтиСообщения ( "Дата согласования*" ).Количество () = 0 ) тогда
    	Стоп ( "Должна быть ошибка неверной установки даты согласования" );
    конецесли;
    
    // Вводим хорошую дату
    товары = Получить ( "!Товары" );
    Установить ( "!ТоварыДатаСогласования [1]", хорошая, товары );
    
    // Проводим документ
    Нажать ( "!ФормаПровести" );
    если ( НайтиСообщения ( "Дата согласования*" ).Количество () > 0 ) тогда
    	Стоп ( "Не должно быть ошибок неверной установки даты согласования" );
    конецесли;
    
    // Закрываем документ не сохраняя
    Закрыть ();
    Нажать ( "Нет", "1*" );

    Комментарии по коду:

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

    Настало время запуска сценария. Для этого убедитесь, что в конфигураторе настроен запуск приложения в режиме клиента тестирования:

    (эта настройка сохраняется и её не придётся устанавливать каждый раз)

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

    Если вы на момент запуска теста еще не реализовали процедуру проверки даты согласования, наш тест упадет.

    Реализуем теперь в модуле реализации, в обработчике ОбработкаПроверкиЗаполнения, такую проверку:

    пустая = Дата ( 1, 1, 1 );
    для каждого строка из Товары цикл
    	согласование = строка.ДатаСогласования;
    	если ( согласование = пустая ) тогда
    		продолжить;
    	иначеесли ( согласование < Дата ) тогда
    		Сообщить ( "Дата согласования установлена неверно" );
    		Отказ = истина;
    	конецесли;
    конеццикла;

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

    Этап 2

    Переходим ко второму запланированному рывку. В таблице ниже состыкуем работу по кодированию и тестированию:

    Программирование Тестирование

    В Конфигураторе: 

    1. Добавляем регистр сведений Согласование
    2. Дорабатываем обработку проведения для формирования записей в регистр

    В Тестере

    Создадим тест ПродажаСДатойСогласования, где:

    1. Определим окружение:
      1. Наименование Поставщика
      2. Наименование Покупателя
      3. Товар1 с ценой и количеством
      4. Товар2 с ценой, количеством и датой согласования
    2. Создадим окружение
      1. Создадим поставщика, покупателя и товары
      2. Сделаем поступление
      3. Создадим и проведем реализацию
    3. Целевая часть
      1. Откроем список реализаций и найдем там созданную реализацию
      2. Откроем реализацию и проведем
      3. Откроем регистр согласований и проверим наличие нашей записи

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

    Для создания окружения, нам будут нужны следующие объекты:

    1. Поставщик
    2. Товар
    3. Склад
    4. Покупатель
    5. Поступление

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

    Метод для создания поставщика

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

    Создадим первый тест-метод. В дереве сценариев, в папке Справочники, создадим папку Поставщики, внутри неё метод Создать, а следом метод Параметры, с тем, чтобы получилась такая структура:

    В результате, у нас получился метод Создать и подчиненный ему метод Параметры. Для того, чтобы в каком-нибудь сценарии воспользоваться этим методом, нам достаточно будет написать такой код:

    // Вначале вызовем тест-метод для получения параметров
    параметры = Вызвать ( "Справочники.Поставщики.Создать.Параметры" );
    
    // Заполняем параметры
    параметры.Наименование = "ТОО Ромашка";
    
    // Запускаем главный метод передавая ему параметры
    Вызвать ( "Справочники.Поставщики.Создать", параметры );

    Справку по всем функциям Тестера см. в разделе API Тестера.

    Для создания сценариев-методов, в форме элемента сценария, на вкладке Свойства, нужно назначить соответствующий тип:

    Подробнее о дереве и свойствах сценариев см. здесь.

    Перейдем в редактор кода сценария Параметры, введем следующий текст:

    // Параметры создания нового элемента
    //
    // Возврат:
    // Структура параметров
    
    СтандартнаяОбработка = ложь;
    
    п = новый Структура ();
    п.Вставить ( "Наименование" );
    п.Вставить ( "Доступ", "Поставщики" );
    
    возврат п;
    

    Затем, откроем редактор сценария Справочники.Поставщики.Создать и введем:

    // Создает нового поставщика по переданным параметрам
    //
    // Параметры:
    // Структура параметров, полученная методом "Справочники.Поставщики.Создать.Параметры"
    //
    // Возврат:
    // Код созданного поставщика
    
    Коммандос ( "e1cib/data/Справочник.Партнеры" );
    
    форма = Здесь ( "Партнер (соз*" );
    
    // *********************************************
    // Заполнение полей
    // *********************************************
    
    Установить ( "!НаименованиеПолноеКомпания", _.Наименование );
    Нажать ( "Поставщик" );
    Установить ( "!ГруппаДоступа", _.Доступ );
    
    // *********************************************
    // Запись, получение кода
    // *********************************************
    
    Нажать ( "!ФормаЗаписать" );
    код = Взять ( "!Код" );
    
    // *********************************************
    // Создание контрагента
    // *********************************************
    
    Нажать ( "Контрагенты", ПолучитьСсылки () );
    список = Здесь ( "Контрагенты*" );
    
    Нажать ( "!ФормаСоздать" );
    Здесь ( "Контрагент (соз*" );
    Установить ( "!Наименование", _.Наименование );
    Нажать ( "!ФормаЗаписатьИЗакрыть" );
    Закрыть ( список );
    
    возврат код;

    Параметризированный метод создания нового поставщика готов. Перейдем к созданию остальных методов.

    Метод для создания покупателя

    Проделаем в дереве сценариев практически те же действия для разработки сценария создания покупателя:

    Затем введем код сценариев, Справочники.Покупатели.Создать.Параметры:

    // Параметры создания нового элемента
    //
    // Возврат:
    // Структура параметров
    
    СтандартнаяОбработка = ложь;
    
    п = новый Структура ();
    п.Вставить ( "Наименование" );
    п.Вставить ( "Доступ", "Прочие" );
    п.Вставить ( "Сделка", "Произвольная продажа" );
    
    возврат п;

    и Справочники.Покупатели.Создать:

    // Создает нового покупателя по переданным параметрам
    //
    // Параметры:
    // Структура параметров, полученная методом "Справочники.Покупатели.Создать.Параметры"
    //
    // Возврат:
    // Код созданного поставщика
    
    Коммандос ( "e1cib/data/Справочник.Партнеры" );
    
    форма = Здесь ( "Партнер (соз*" );
    
    // *********************************************
    // Заполнение полей
    // *********************************************
    
    Установить ( "!НаименованиеПолноеКомпания", _.Наименование );
    Нажать ( "!Клиент" );
    Установить ( "!ГруппаДоступа", _.Доступ );
    
    // *********************************************
    // Запись, получение кода
    // *********************************************
    
    Нажать ( "!ФормаЗаписать" );
    код = Взять ( "!Код" );
    
    // *********************************************
    // Создание контрагента
    // *********************************************
    
    Нажать ( "Контрагенты", ПолучитьСсылки () );
    список = Здесь ( "Контрагенты*" );
    
    Нажать ( "!ФормаСоздать" );
    Здесь ( "Контрагент (соз*" );
    Установить ( "!Наименование", _.Наименование );
    Нажать ( "!ФормаЗаписатьИЗакрыть" );
    Закрыть ( список );
    
    возврат код;

    Метод для создания товаров

    Справочники.Номенклатура.Создать.Параметры

    // Параметры создания нового элемента
    //
    // Возврат:
    // Структура параметров
    
    п = новый Структура ();
    п.Вставить ( "Наименование" );
    п.Вставить ( "Единица", "шт" );
    п.Вставить ( "Вид", "Товар" );
    п.Вставить ( "СтавкаНДС", "18%" );
    возврат п;

    Справочники.Номенклатура.Создать

    // Создает новую номенклатуру по переданным параметрам
    //
    // Параметры:
    // Структура параметров, полученная методом "Справочники.Номенклатура.Создать.Параметры"
    //
    // Возврат:
    // Код созданной номенклатуры
    
    Коммандос ( "e1cib/data/Справочник.Номенклатура" );
    
    форма = Здесь ( "Номенклатура (соз*" );
    
    // *********************************************
    // Заполнение полей
    // *********************************************
    
    //установитьВид ( форма, _.Вид );
    Установить ( "!ВидНоменклатурыОбязательныеПоля", _.Вид );
    Установить ( "Рабочее наименование", _.Наименование );
    Установить ( "Единица хранения", _.Единица );
    Установить ( "Ставка НДС", _.СтавкаНДС );
    
    // *********************************************
    // Запись, получение кода и завершение
    // *********************************************
    
    Нажать ( "!ФормаЗаписать" );
    код = Взять ( "!Код" );
    
    Закрыть ();
    
    возврат код;

    Метод для создания складов

    Справочники.Склады.Создать.Параметры

    // Параметры создания нового элемента
    //
    // Возврат:
    // Структура параметров
    
    п = новый Структура ();
    п.Вставить ( "Наименование" );
    возврат п;

    Справочники.Склады.Создать

    // Создает новый склад по переданным параметрам
    //
    // Параметры:
    // Структура параметров, полученная методом "Справочники.Склады.Создать.Параметры"
    
    Коммандос ( "e1cib/data/Справочник.Склады" );
    
    форма = Здесь ( "* (соз*" );
    
    // *********************************************
    // Заполнение полей
    // *********************************************
    
    Установить ( "!Наименование", _.Наименование );
    Установить ( "!ТипСкладаОптовый", "Оптовый склад" );
    
    // *********************************************
    // Запись, получение кода и завершение
    // *********************************************
    
    Нажать ( "!ФормаЗаписатьИЗакрыть" );

    Метод для создания документа ПоступлениеТоваровУслуг

    Документы.ПоступлениеТоваровУслуг.Создать.Параметры

    // Параметры создания нового документа
    //
    // Возврат:
    // Структура параметров
    
    СтандартнаяОбработка = ложь;
    
    п = новый Структура ();
    п.Вставить ( "Дата" );
    п.Вставить ( "Организация", __.Организация );
    п.Вставить ( "Склад" );
    п.Вставить ( "Поставщик" );
    п.Вставить ( "Товары", новый Массив ); // Массив Документы.ЗаказПоставщику.Создать.Строка
    п.Вставить ( "ОставитьОткрытым", ложь ); // Закрыть или оставить на экране форму документа
    
    возврат п;

    Документы.ПоступлениеТоваровУслуг.Создать.Товар

    // Параметры создания новой строки документа
    //
    // Возврат:
    // Структура параметров
    
    СтандартнаяОбработка = ложь;
    
    п = новый Структура ();
    п.Вставить ( "Товар" ); // Наименование или Код товара
    п.Вставить ( "Количество" );
    п.Вставить ( "Цена" );
    
    возврат п;

    Документы.ПоступлениеТоваровУслуг.Создать

    // Создает новый документ Поступление товаров и услуг по переданным параметрам
    //
    // Параметры:
    // Структура параметров, полученная методом "Документы.ПоступлениеТоваровУслуг.Создать.Параметры"
    //
    // Возврат:
    // Номер созданного заказа
    
    Коммандос ( "e1cib/data/Документ.ПоступлениеТоваровУслуг" );
    
    форма = Здесь ( "Поступление товаров и услуг (соз*" );
    
    // *********************************************
    // Заполнение шапки
    // *********************************************
    
    дата = _.Дата;
    если ( дата <> неопределено ) тогда
    	Установить ( "!Дата", Формат ( дата, "DLF=DT" ) );
    конецесли;
    
    Установить ( "!Партнер", _.Поставщик );
    Установить ( "!Организация", _.Организация );
    
    значение = _.Склад;
    если ( значение <> неопределено ) тогда
    	Установить ( "!Склад", значение );
    конецесли;
    
    // *********************************************
    // Заполнение товаров
    // *********************************************
    
    таблица = Фокус ( "!Товары" );
    для каждого товар из _.Товары цикл
    
    	Нажать ( "!ТоварыДобавить", таблица );
    	Установить ( "!ТоварыНоменклатура", товар.Товар );
    	Установить ( "!ТоварыКоличествоУпаковок", товар.Количество );
    	Установить ( "!ТоварыЦена", товар.Цена );
    
    конеццикла;
    
    // *********************************************
    // Запись документа, получение номера
    // *********************************************
    
    Нажать ( "!ФормаЗаписать" );
    номер = Взять ( "!Номер" );
    
    // *********************************************
    // Проведение документа и возврат номера
    // *********************************************
    
    Нажать ( "!ФормаПровести" );
    
    закрыть = не _.ОставитьОткрытым;
    если ( закрыть ) тогда
    	Закрыть ();
    конецесли;
    
    возврат номер;

    Метод для создания документа РеализацияТоваровУслуг

    Документы.РеализацияТоваровУслуг.Создать.Параметры

    // Параметры создания нового документа
    //
    // Возврат:
    // Структура параметров
    
    СтандартнаяОбработка = ложь;
    
    п = новый Структура ();
    п.Вставить ( "Дата" );
    п.Вставить ( "Организация", __.Организация );
    п.Вставить ( "Склад" );
    п.Вставить ( "Покупатель" );
    п.Вставить ( "Товары", новый Массив ); // Массив Документы.ЗаказПоставщику.Создать.Строка
    п.Вставить ( "ОставитьОткрытым", ложь ); // Закрыть или оставить на экране форму документа
    п.Вставить ( "Комментарий" );
    
    возврат п;

    Документы.РеализацияТоваровУслуг.Создать.Товар

    // Параметры создания новой строки документа
    //
    // Возврат:
    // Структура параметров
    
    СтандартнаяОбработка = ложь;
    
    п = новый Структура ();
    п.Вставить ( "Товар" ); // Наименование или Код товара
    п.Вставить ( "Количество" );
    п.Вставить ( "Цена" );
    п.Вставить ( "Согласование" );
    
    возврат п;

    Документы.РеализацияТоваровУслуг.Создать

    // Создает новый документ Реализация товаров и услуг по переданным параметрам
    //
    // Параметры:
    // Структура параметров, полученная методом "Документы.РеализацияТоваровУслуг.Создать.Параметры"
    //
    // Возврат:
    // Номер созданного заказа
    
    Коммандос ( "e1cib/data/Документ.РеализацияТоваровУслуг" );
    
    форма = Здесь ( "Реализация товаров и услуг (соз*" );
    
    // *********************************************
    // Заполнение шапки
    // *********************************************
    
    дата = _.Дата;
    если ( дата <> неопределено ) тогда
    	Установить ( "!Дата", Формат ( дата, "DLF=DT" ) );
    конецесли;
    
    Установить ( "!Партнер", _.Покупатель );
    Установить ( "!Организация", _.Организация );
    
    значение = _.Склад;
    если ( значение <> неопределено ) тогда
    	Установить ( "!Склад", значение );
    конецесли;
    
    значение = _.Комментарий;
    если ( значение <> неопределено ) тогда
    	Установить ( "!Комментарий", значение );
    конецесли;
    
    // *********************************************
    // Заполнение товаров
    // *********************************************
    
    таблица = Фокус ( "!Товары" );
    никогда = Дата ( 1, 1, 1 );
    для каждого товар из _.Товары цикл
    
    	Нажать ( "!ТоварыДобавить", таблица );
    	Установить ( "!ТоварыНоменклатура", товар.Товар );
    	Установить ( "!ТоварыКоличествоУпаковок", товар.Количество );
    	Очистить ( "!ТоварыВидЦены" );
    	Установить ( "!ТоварыЦена", товар.Цена );
    	согласование = товар.Согласование;
    	если ( согласование <> никогда ) тогда
    		Установить ( "!ТоварыДатаСогласования", Формат ( согласование, "DLF=D" ) );
    	конецесли;
    
    конеццикла;
    
    // *********************************************
    // Запись документа, получение номера
    // *********************************************
    
    Нажать ( "!ФормаЗаписать" );
    номер = Взять ( "!Номер" );
    
    // *********************************************
    // Проведение документа и возврат номера
    // *********************************************
    
    Нажать ( "!ФормаПровести" );
    
    закрыть = не _.ОставитьОткрытым;
    если ( закрыть ) тогда
    	Закрыть ();
    конецесли;
    
    возврат номер;

    На этом, подготовка методов закончена.

    Создание теста ПродажаСДатойСогласования

    Переходим к написанию конечного теста для второго этапа. Для этого, в дереве сценариев, создадим такой тест:

    Сделаем его основным, и внесем следующий код:

    // Сценарий:
    // - Создадим окружение в результате которого будет существовать документ
    //   реализация с двумя товарами, для второго товара указана дата согласования
    // - Откроем список реализаций
    // - Найдем созданную реализацию и (пере)проведем её
    // - Откроем регистр согласований и найдем там запись, которую должна была сделать реализация
    // - Проверим правильность сформированной записи
    
    Вызвать ( "Общее.Начало" );
    ЗакрытьВсё ();
    
    ид = "25C555B6";
    тест = окружение ( ид );
    создатьОкружение ( тест );
    
    // ************************************
    // Целевой сценарий
    // ************************************
    
    // Откроем реализации
    Коммандос ( "e1cib/list/Документ.РеализацияТоваровУслуг" );
    Здесь ( "Документы реализации" );
    
    // Перейдем к нашему документу
    Кстроке ( "!СписокРеализацииТоваровУслуг", "Клиент", тест.Покупатель );
    
    // Проведем
    Нажать ( "!СписокРеализацииТоваровУслугПровести" );
    
    // Откроем регистр согласований
    Коммандос ( "e1cib/list/РегистрСведений.Согласование" );
    Здесь ( "Согласование" );
    
    // Перейдем к записи
    ок = Кстроке ( "!Список", "Клиент", тест.Покупатель );
    если ( не ок ) тогда
    	Стоп ( "После проведения реализации не сформировались записи в регистре Согласование" );
    конецесли;
    
    // Проверим правильность сформированной записи.
    // Выведем стандартный список
    Нажать ( "!ФормаВывестиСписок" );
    Здесь ( "Вывести список" );
    
    // Включим флажок "Только выделенные"
    было = Взять ( "!OnlySelectedElement" );
    если ( было = "Нет" ) тогда
    	Нажать ( "!OnlySelectedElement" );
    конецесли;
    
    // Укажем, что выводить будем в табличный документ
    Подобрать ( "!DocumentTypeElement", "Табличный документ" );
    
    // Формируем мини-отчет
    Нажать ( "!Ok" );
    
    // Просим тестер проверить этот отчет
    Здесь ( "Список" );
    ПроверитьШаблон ( "" );
    
    // *********************************************
    // Процедуры
    // *********************************************
    
    Функция окружение ( ИД )
    
    	дата = ТекущаяДата ();
    	п = новый Структура ();
    	п.Вставить ( "ИД", ИД );
    	п.Вставить ( "Дата", дата );
    	п.Вставить ( "Согласование", ТекущаяДата () + 172800 ); // Через два дня
    	п.Вставить ( "ДатаПоступления", дата - 86400 );
    	п.Вставить ( "Поставщик", "Поставщик " + ИД );
    	п.Вставить ( "Покупатель", "Покупатель " + ИД );
    	п.Вставить ( "Склад", "Склад " + ИД );
    	п.Вставить ( "Товары", определитьТовары ( п ) );
    	возврат п;
    
    КонецФункции
    
    Функция определитьТовары ( Тест )
    
    	ид = Тест.ИД;
    	список = новый Массив ();
    	список.Добавить ( новыйТовар ( "Товар1 " + ид, 5, 150, 250 ) );
    	список.Добавить ( новыйТовар ( "Товар2 " + ид, 15, 250, 350, Тест.Согласование ) );
    	возврат список;
    
    КонецФункции
    
    Функция новыйТовар ( Товар, Количество, Стоимость, Цена, Согласование = неопределено )
    
    	п = новый Структура ();
    	п.Вставить ( "Товар", Товар );
    	п.Вставить ( "Количество", Количество );
    	п.Вставить ( "Стоимость", Стоимость );
    	п.Вставить ( "Цена", Цена );
    	п.Вставить ( "Согласование", Согласование );
    	возврат п;
    
    КонецФункции
    
    Процедура создатьОкружение ( Тест )
    
    	ид = Тест.ИД;
    	
    	// *****************************************************
    	// Проверяем, нужно ли создавать данные для тестирования
    	// *****************************************************
    	
    	если ( СозданоОкружение ( ид ) ) тогда
    		возврат;
    	конецесли;
    	
    	// ******************************************************************
    	// Проверим, чтобы в настройках были отключены соглашения с клиентами
    	// ******************************************************************
    	
    	Коммандос ( "e1cib/command/Обработка.ПанельАдминистрированияУТ.Команда.Продажи" );
    	Здесь ( "Продажи" );
    	опция = Взять ( "!ИспользованиеСоглашенийСКлиентами" );
    	если ( опция <> "Не использовать" ) тогда
    		Стоп ( "В целях обучения, этап создания соглашений с клиентами в сценариях не предусмотрен.
    		|В окне, которое сейчас на экране с тестируемым приложением, откройте группу
    		|Оптовые продажи и в поле Использование соглашений с клиентами, выберите Не использовать" );
    	конецесли;
    	
    	// ******************
    	// Создаем склад
    	// ******************
    	
    	п = Вызвать ( "Справочники.Склады.Создать.Параметры" );
    	п.Наименование = Тест.Склад;
    	Вызвать ( "Справочники.Склады.Создать", п );
    
    	// ******************
    	// Создаем поставщика
    	// ******************
    	
    	п = Вызвать ( "Справочники.Поставщики.Создать.Параметры" );
    	п.Наименование = Тест.Поставщик;
    	Вызвать ( "Справочники.Поставщики.Создать", п );
    
    	// ******************
    	// Создаем покупателя
    	// ******************
    	
    	п = Вызвать ( "Справочники.Покупатели.Создать.Параметры" );
    	п.Наименование = Тест.Покупатель;
    	Вызвать ( "Справочники.Покупатели.Создать", п );
    
    	// **************
    	// Создаем товары
    	// **************
    	
    	для каждого товар из Тест.Товары цикл
    		п = Вызвать ( "Справочники.Номенклатура.Создать.Параметры" );
    		п.Наименование = товар.Товар;
    		Вызвать ( "Справочники.Номенклатура.Создать", п );
    	конеццикла;
    
    	// *******************
    	// Создаем поступление
    	// *******************
    	
    	товары = новый Массив ();
    	для каждого позиция из тест.Товары цикл
    		товар = Вызвать ( "Документы.ПоступлениеТоваровУслуг.Создать.Товар" );
    		товар.Товар = позиция.Товар;
    		товар.Количество = позиция.Количество;
    		товар.Цена = позиция.Стоимость;
    		товары.Добавить ( товар );
    	конеццикла;
    
    	п = Вызвать ( "Документы.ПоступлениеТоваровУслуг.Создать.Параметры" );
    	п.Товары = товары;
    	п.Дата = тест.ДатаПоступления;
    	п.Поставщик = тест.Поставщик;
    	п.Склад = тест.Склад;
    
    	Вызвать ( "Документы.ПоступлениеТоваровУслуг.Создать", п );
    	
    	// *******************
    	// Создаем реализацию
    	// *******************
    	
    	товары = новый Массив ();
    	для каждого позиция из тест.Товары цикл
    		товар = Вызвать ( "Документы.РеализацияТоваровУслуг.Создать.Товар" );
    		товар.Товар = позиция.Товар;
    		товар.Количество = позиция.Количество;
    		товар.Цена = позиция.Цена;
    		товар.Согласование = позиция.Согласование;
    		товары.Добавить ( товар );
    	конеццикла;
    
    	п = Вызвать ( "Документы.РеализацияТоваровУслуг.Создать.Параметры" );
    	п.Товары = товары;
    	п.Дата = тест.Дата;
    	п.Покупатель = тест.Покупатель;
    	п.Склад = тест.Склад;
    
    	Вызвать ( "Документы.РеализацияТоваровУслуг.Создать", п );
    	
    	// ********************************
    	// Регистрируем созданное окружение
    	// ********************************
    	
    	СохранитьОкружение ( ид );
    
    КонецПроцедуры

    Так как это наш главный сценарий для второго этапа, разберем его подробней.

    Сценарий начинается с Вызвать ( "Общее.Начало" );. Я делаю этот вызов для задания глобальных переменных и выполнения общих задач перед началом работы любого теста. Посмотрим, что внутри теста Общее.Начало:

    // Начальный скрипт для инициализации глобального окружения процесса тестирования
    // В скрипте могут задаваться общие параметры, которые могут быть доступны во всех
    // остальных сценариях
    
    СтандартнаяОбработка = ложь;
    
    если ( __ = неопределено ) тогда
    	__ = новый Структура ();
    иначе
    	возврат;
    конецесли;
    
    // *************************************************************************
    // Используем переменную "__" для задания произвольных глобальных параметров
    // *************************************************************************
    
    __.Вставить ( "ПроверятьЛогику", истина );
    __.Вставить ( "ЛокальнаяВалюта", "РУБ" );
    
    если ( ИмяПриложения = "УТ11" ) тогда
    	__.Вставить ( "Организация", "Торговый дом ""Комплексный""" );
    конецесли;
    
    // ***********************************************
    // Выполняем подключение к тестируемому приложению
    // ***********************************************
    
    Подключить ();

    Если вы используете демо-базу Тестера, тогда тест Общее.Начало там уже есть. Откройте этот тест и внесите в него изменения, в частности, нам нужна вот эта часть модуля:

    если ( ИмяПриложения = "УТ11" ) тогда
    	__.Вставить ( "Организация", "Торговый дом ""Комплексный""" );
    конецесли;

    Работает это всё следующим образом. Когда тест ПродажаСДатойСогласования будет запущен, он в свою очередь запустит тест Общее.Начало, который определит несколько переменных и подключится к тестируемому приложению. Все тесты, которые будут запускаться дальше, уже будут знать, что в переменной “__” хранится имя организации, локальная валюта и другие параметры. Это своего рода глобальное параметризирование тестируемой среды (использование двойного подчеркивания в качестве глобальной переменной выбрано для независимости от варианта языка 1С).

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

    Следующие три строки определяют и создают окружение (см. Структура сценария):

    // Переменная "ид" задает идентификатор окружения.
    // Идентификатор окружения может быть любой, но я рекомендую использовать
    // указанный ниже шаблон алфавитно-цифровой последовательности,
    // которая может быть автоматически сгенерирована в редакторе модуля
    // по комбинации клавиш: Ctrl+Shit+I
    // Таким образом, чтобы пересоздать окружение, нужно будет просто сменить "ид".
    // Почему это так - будет понятно ниже.
    ид = "25C555B6";
    
    // В переменную "тест" функция окружение () вернет структуру с параметрами
    // нашего теста. Эти параметры и есть определение окружения.
    тест = окружение ( ид );
    
    // Процедура создатьОкружение () выполняет создание необходимых тестовых данных.
    // Внутри этой процедуры будут вызываться тесты-методы, которые мы создавали в разделах выше.
    создатьОкружение ( тест );

    Посмотрим, что происходит внутри функции окружение ():

    Функция окружение ( ИД )
    
    	дата = ТекущаяДата ();
    	п = новый Структура ();
    	п.Вставить ( "ИД", ИД );
    	п.Вставить ( "Дата", дата );
    	п.Вставить ( "Согласование", ТекущаяДата () + 172800 ); // Через два дня
    	п.Вставить ( "ДатаПоступления", дата - 86400 );
    	п.Вставить ( "Поставщик", "Поставщик " + ИД );
    	п.Вставить ( "Покупатель", "Покупатель " + ИД );
    	п.Вставить ( "Склад", "Склад " + ИД );
    	п.Вставить ( "Товары", определитьТовары ( п ) );
    	возврат п;
    
    КонецФункции

    Ничего необычного, готовится структура с параметрами, но концептуальным является использование входящего параметра ИД.

    Тестовые данные создаются, а значит, они должны быть уникальны. В противном случае, будут создаваться дубли объектов, которые практически, будет невозможно использовать. Действительно, если мы будем создавать “ТОО Ромашка" каждый раз, какую тогда "ТОО Ромашка" выбрать при создании документа? Таким образом, строки кода "Поставщик " + ИД, "Покупатель " + ИД и другие, гарантируют создание уникальных тестовых данных. Это также позволяет выполнять ваши тесты у других участников разработки, без синхронизации заготовленных шаблонов, использования предзаполненных баз данных и других внешних файлов.

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

    Другой, кажущийся тревожным момент – это глубина уникальности тестовых данных и их объем. И тут нужно отметить, что не все тестовые данные нужно делать уникальными. Уникальности требует только то, что вам нужно для тестирования (включая проверку бизнес логики). К примеру, для нашего теста нужна уникальность наименований поставщика, покупателя, склада и товаров. Нам не требуется уникальность единиц измерений, договоров, соглашений, групп товаров и других связанных данных. Рост данных также не будет проблемой. Даже если вы каждые 5 минут запускаете тест создающий окружение (что крайне маловероятно), то в течение дня таких запусков будет не больше 100, что для дневного роста базы ничтожно мало. На практике, необходимость в обнулении рабочей базы загрузкой в неё начальной, возникает примерно раз в полгода. Согласитесь, что программисты, тестирующие всё вручную, примерно с той же периодичностью выводят из строя свои рабочие базы.

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

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

    Процедура создатьОкружение ( Тест )
    
    	ид = Тест.ИД;
    	
    	// *****************************************************
    	// Проверяем, нужно ли создавать данные для тестирования
    	// *****************************************************
    	
    	если ( СозданоОкружение ( ид ) ) тогда
    		возврат;
    	конецесли;
    	
    	// ...код создания окружения...
    
    	// ********************************
    	// Регистрируем созданное окружение
    	// ********************************
    	
    	СохранитьОкружение ( ид );
    
    КонецПроцедуры

    Методы СозданоОкружение/СохранитьОкружение работают с идентификатором по ключу компьютер + имя пользователя.

    Примечание: Переход к строке сделан через попытку, потому что в версиях платформы <= 8.3.9 есть ошибка работы метода перехода к строке. В случае отсутствия искомой строки, платформа ошибочно генерирует исключение вместо возврата булевого значения.

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

    Подключить ();
    
    // Отлаживаем по-быстрому...
    п = Вызвать ( "Справочники.Склады.Создать.Параметры" );
    п.Наименование = "Тестовый склад";
    Вызвать ( "Справочники.Склады.Создать", п );
    
    возврат; // Когда отладим, вырежем этот код в тело процедуры создатьОкружение ()
    
    // Сценарий:
    // - Создадим окружение в результате которого будет существовать документ
    //   реализация с двумя товарами, для второго товара указана дата согласования
    // - Откроем список реализаций
    // - Найдем созданную реализацию и (пере)проведем её
    // - Откроем регистр согласований и найдем там запись, которую должна была сделать реализация
    // - Проверим правильность сформированной записи
    
    Вызвать ( "Общее.Начало" );
    ЗакрытьВсё ();
    
    // ....

    Таким образом, кусок за куском логики можно отлаживать и переносить в процедуру создатьОкружение (). Обратите внимание, что для пересоздания всего окружения, вам просто нужно будет сменить ИД в начале теста.

    Я описал определение и создание окружения, перейдем теперь к целевой части сценария ПродажаСДатойСогласования:

    // Откроем реализации
    Коммандос ( "e1cib/list/Документ.РеализацияТоваровУслуг" );
    Здесь ( "Документы реализации" );
    
    // Перейдем к нашему документу
    Кстроке ( "!СписокРеализацииТоваровУслуг", "Клиент", тест.Покупатель );
    
    // Проведем
    Нажать ( "!СписокРеализацииТоваровУслугПровести" );
    
    // Откроем регистр согласований
    Коммандос ( "e1cib/list/РегистрСведений.Согласование" );
    Здесь ( "Согласование" );
    
    // Перейдем к записи
    ок = Кстроке ( "!Список", "Клиент", тест.Покупатель );
    если ( не ок ) тогда
    	Стоп ( "После проведения реализации не сформировались записи в регистре Согласование" );
    конецесли;
    
    // Проверим правильность сформированной записи.
    // Выведем стандартный список
    Нажать ( "!ФормаВывестиСписок" );
    Здесь ( "Вывести список" );
    
    // Включим флажок "Только выделенные"
    было = Взять ( "!OnlySelectedElement" );
    если ( было = "Нет" ) тогда
    	Нажать ( "!OnlySelectedElement" );
    конецесли;
    
    // Укажем, что выводить будем в табличный документ
    Подобрать ( "!DocumentTypeElement", "Табличный документ" );
    
    // Формируем мини-отчет
    Нажать ( "!Ok" );
    
    // Просим тестер проверить этот отчет
    Здесь ( "Список" );
    ПроверитьШаблон ( "" );

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

    Нажать ( "!ФормаВывестиСписок" );
    Здесь ( "Вывести список" );
    // и далее...

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

    Здесь ( "Список" );
    ПроверитьШаблон ( "" );

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

    Если мы сейчас запустим сценарий на выполнение, он упадет на этапе создания окружения, ведь у нас кроме логики проведения, еще нет реквизита ДатаСогласования в табличной части Товары документа РеализацияТоваровУслуг.

    Займемся программированием:

    - Добавим нужный реквизит:

    - Выведем на форму:

    - В процедуру ОбработкаПроведения модуля объекта, добавим код:

    Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    	с = "
    	|выбрать Товары.Ссылка.Менеджер как Менеджер, Товары.Ссылка.Партнер как Клиент,
    	|	Товары.Номенклатура как Товар, Товары.Количество как Количество, Товары.Сумма как Сумма,
    	|	Товары.КодСтроки как Строка, Товары.ДатаСогласования как ДатаСогласования,  &Ссылка как Реализация
    	|из Документ.РеализацияТоваровУслуг.Товары как Товары
    	|	//
    	|	// Согласованные
    	|	//
    	|	левое соединение РегистрСведений.Согласование как Согласованные
    	|	по Согласованные.Строка = Товары.КодСтроки
    	|где Товары.Ссылка = &Ссылка
    	|и Товары.ДатаСогласования <> датавремя ( 1, 1, 1 )
    	|и не isnull ( Согласованные.Отработано, ложь )
    	|";
    	з = новый Запрос ( с );
    	з.УстановитьПараметр ( "Ссылка", Ссылка );
    	таблица = з.Выполнить ().Выгрузить ();
    	для каждого строка из таблица цикл
    		запись = РегистрыСведений.Согласование.СоздатьМенеджерЗаписи ();
    		ЗаполнитьЗначенияСвойств ( запись, строка );
    		запись.Записать ();
    	конеццикла;
    
    // ...далее идет типовой код конфигурации

    Примечание: Чтобы оставаться в фарватере изложения, я опускаю некоторые детали реализации. Например, вы наверняка обратили внимание на отсутствие отработки ситуации удаления строки из табличной части, ранее которая была на согласовании.

    Запускаем приложение, запускаем тест. После завершения теста, у вас должно получиться это:

    Выделите в УТ11 этот макет и скопируйте в Тестер на вкладку Шаблон сценария ПродажаСДатойСогласования. Затем, в Тестере, выделите значимую область, вызовите правым кликом контекстное меню и укажите Отметить область:

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

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

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

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

    Переходим к следующему запланированному этапу.

    Этап 3

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

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

    Программирование Тестирование

    В Конфигураторе: 

    1. Добавляем форму списка в регистр сведений Согласование
    2. Создаем три реквизита формы соответствующих типов, выкладываем их на форму
    3. Настраиваем свойства и обработчики
    4. Прописываем код обработчиков фильтрации

    В Тестере

    Создадим тест ФильтрацияСписка, где:

    1. Определим окружение:
      1. Наименование Поставщика
      2. Наименование Покупателя
      3. Наименование Потенциального клиента, по которому продаж нет
      4. Товар с датой согласования
    2. Создадим окружение
      1. Создадим поставщика, покупателей и товар
      2. Сделаем поступление
      3. Создадим и проведем реализацию
    3. Целевая часть
      1. Откроем список регистра Согласование
      2. Установим отбор по покупателю, проверим список
      3. Установим отбор по потенциальному клиенту, проверим пустой список
      4. Установим/снимем отборы по товару и менеджеру

    Для разнообразия, в этот раз начнем с программирования, а затем напишем тест.

    - Добавим основную форму списка, добавим реквизиты формы, расположим на форме:

    - В модуле формы списка, определим обработчики полей фильтрации:

    &НаКлиенте
    Процедура КлиентФильтрПриИзменении ( Элемент )
    	
    	ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(Список,
    		"Клиент",
    		КлиентФильтр,
    		ВидСравненияКомпоновкиДанных.Равно,
    		,
    		ЗначениеЗаполнено(КлиентФильтр));
    	
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ТоварФильтрПриИзменении ( Элемент )
    	
    	ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(Список,
    		"Товар",
    		ТоварФильтр,
    		ВидСравненияКомпоновкиДанных.Равно,
    		,
    		ЗначениеЗаполнено(ТоварФильтр));
    	
    КонецПроцедуры
    
    &НаКлиенте
    Процедура МенеджерФильтрПриИзменении ( Элемент )
    	
    	ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(Список,
    		"Менеджер",
    		МенеджерФильтр,
    		ВидСравненияКомпоновкиДанных.Равно,
    		,
    		ЗначениеЗаполнено(МенеджерФильтр));
    	
    КонецПроцедуры

    На этом этапе с программированием всё. Перейдем к разработке теста. Для этого, как и в прошлые разы, в дереве сценариев, создадим новый сценарий. Установим этот сценарий основным, и назовем его ФильтрацияСписка:

    Введем следующий код сценария:

    // Сценарий:
    // - Создадим окружение в результате которого будет существовать проведенный документ
    //   реализация с товаром, для которого указана дата согласования
    // - Откроем список Согласование
    // - Установим отбор по покупателю, убедимся, что в списке есть отфильтрованная запись
    // - Установим отбор по потенциальному клиенту, убедимся, что список пуст
    // - Очистим фильтры по товару и менеджеру, проверим что они отрабатывают,
    //   допускаем, что если нет ошибок тогда фильтрация происходит
    
    Вызвать ( "Общее.Начало" );
    ЗакрытьВсё ();
    
    ид = "25CB69CB";
    тест = окружение ( ид );
    создатьОкружение ( тест );
    
    // ************************************
    // Целевой сценарий
    // ************************************
    
    // Откроем регистр согласований
    Коммандос ( "e1cib/list/РегистрСведений.Согласование" );
    Здесь ( "Согласование" );
    
    // Установим фильтр по покупателю
    покупатель = тест.Покупатель;
    Ввести ( "!КлиентФильтр", покупатель );
    
    // Найдем его в списке
    ок = Кстроке ( "!Список", "Клиент", покупатель );
    если ( не ок ) тогда
    	Стоп ( "В списке не найдена отфильтрованная по клиенту запись" );
    конецесли;
    
    // Установим фильтр по потенциальному клиенту
    Ввести ( "!КлиентФильтр", тест.ПотенциальныйКлиент );
    
    // Список должен быть пустой
    пусто = 0 = Вызвать ( "Таблица.Количество", Получить ( "!Список" ) );
    если ( не пусто ) тогда
    	Стоп ( "Список должен быть пуст" );
    конецесли;
    Очистить ( "!КлиентФильтр" );
    
    // Установим и очистим фильтр по товару
    Ввести ( "!ТоварФильтр", тест.Товары [ 0 ].Товар );
    Очистить ( "!ТоварФильтр" );
    
    // Очистим фильтр по менеджеру
    Очистить ( "!МенеджерФильтр" );
    
    // *********************************************
    // Процедуры
    // *********************************************
    
    Функция окружение ( ИД )
    
    	дата = ТекущаяДата ();
    	п = новый Структура ();
    	п.Вставить ( "ИД", ИД );
    	п.Вставить ( "Дата", дата );
    	п.Вставить ( "Согласование", дата + 172800 ); // Через два дня
    	п.Вставить ( "ДатаПоступления", дата - 86400 );
    	п.Вставить ( "Поставщик", "Поставщик " + ИД );
    	п.Вставить ( "Покупатель", "Покупатель " + ИД );
    	п.Вставить ( "ПотенциальныйКлиент", "Потенциальный клиент " + ИД );
    	п.Вставить ( "Склад", "Склад " + ИД );
    	п.Вставить ( "Товары", определитьТовары ( п ) );
    	возврат п;
    
    КонецФункции
    
    Функция определитьТовары ( Тест )
    
    	ид = Тест.ИД;
    	список = новый Массив ();
    	список.Добавить ( новыйТовар ( "Товар1 " + ид, 15, 250, 350, Тест.Согласование ) );
    	возврат список;
    
    КонецФункции
    
    Функция новыйТовар ( Товар, Количество, Стоимость, Цена, Согласование = неопределено )
    
    	п = новый Структура ();
    	п.Вставить ( "Товар", Товар );
    	п.Вставить ( "Количество", Количество );
    	п.Вставить ( "Стоимость", Стоимость );
    	п.Вставить ( "Цена", Цена );
    	п.Вставить ( "Согласование", Согласование );
    	возврат п;
    
    КонецФункции
    
    Процедура создатьОкружение ( Тест )
    
    	ид = Тест.ИД;
    	
    	// *****************************************************
    	// Проверяем, нужно ли создавать данные для тестирования
    	// *****************************************************
    	
    	если ( СозданоОкружение ( ид ) ) тогда
    		возврат;
    	конецесли;
    	
    	// ******************
    	// Создаем склад
    	// ******************
    	
    	п = Вызвать ( "Справочники.Склады.Создать.Параметры" );
    	п.Наименование = Тест.Склад;
    	Вызвать ( "Справочники.Склады.Создать", п );
    
    	// ******************
    	// Создаем поставщика
    	// ******************
    	
    	п = Вызвать ( "Справочники.Поставщики.Создать.Параметры" );
    	п.Наименование = Тест.Поставщик;
    	Вызвать ( "Справочники.Поставщики.Создать", п );
    
    	// *******************
    	// Создаем покупателей
    	// *******************
    	
    	п = Вызвать ( "Справочники.Покупатели.Создать.Параметры" );
    	п.Наименование = Тест.Покупатель;
    	Вызвать ( "Справочники.Покупатели.Создать", п );
    
    	п.Наименование = Тест.ПотенциальныйКлиент;
    	Вызвать ( "Справочники.Покупатели.Создать", п );
    	
    	// **************
    	// Создаем товары
    	// **************
    	
    	для каждого товар из Тест.Товары цикл
    		п = Вызвать ( "Справочники.Номенклатура.Создать.Параметры" );
    		п.Наименование = товар.Товар;
    		Вызвать ( "Справочники.Номенклатура.Создать", п );
    	конеццикла;
    
    	// *******************
    	// Создаем поступление
    	// *******************
    	
    	товары = новый Массив ();
    	для каждого позиция из тест.Товары цикл
    		товар = Вызвать ( "Документы.ПоступлениеТоваровУслуг.Создать.Товар" );
    		товар.Товар = позиция.Товар;
    		товар.Количество = позиция.Количество;
    		товар.Цена = позиция.Стоимость;
    		товары.Добавить ( товар );
    	конеццикла;
    
    	п = Вызвать ( "Документы.ПоступлениеТоваровУслуг.Создать.Параметры" );
    	п.Товары = товары;
    	п.Дата = тест.ДатаПоступления;
    	п.Поставщик = тест.Поставщик;
    	п.Склад = тест.Склад;
    
    	Вызвать ( "Документы.ПоступлениеТоваровУслуг.Создать", п );
    	
    	// *******************
    	// Создаем реализацию
    	// *******************
    	
    	товары = новый Массив ();
    	для каждого позиция из тест.Товары цикл
    		товар = Вызвать ( "Документы.РеализацияТоваровУслуг.Создать.Товар" );
    		товар.Товар = позиция.Товар;
    		товар.Количество = позиция.Количество;
    		товар.Цена = позиция.Цена;
    		товар.Согласование = позиция.Согласование;
    		товары.Добавить ( товар );
    	конеццикла;
    
    	п = Вызвать ( "Документы.РеализацияТоваровУслуг.Создать.Параметры" );
    	п.Товары = товары;
    	п.Дата = тест.Дата;
    	п.Покупатель = тест.Покупатель;
    	п.Склад = тест.Склад;
    
    	Вызвать ( "Документы.РеализацияТоваровУслуг.Создать", п );
    	
    	// ********************************
    	// Регистрируем созданное окружение
    	// ********************************
    	
    	СохранитьОкружение ( ид );
    
    КонецПроцедуры

    Комментарии по коду теста:

    1. Фактически, этот сценарий является упрощенной версией сценария, который мы создали на предыдущем этапе.
    2. Я опустил в этом сценарии проверку настройки соглашений с клиентами, в реальном проекте вы эту настройку выделите в отдельный тест проверки окружения и не будете включать в каждый ваш тест.
    3. В этом сценарии используется библиотечный тест Вызвать ( "Таблица.Количество", Получить ( "!Список" ) ). Хороший пример того, как можно общую логику по работе с объектами системы выделять в отдельные тесты.
    4. Чистого времени на разработку этого теста, у освоившего Тестер программиста уходит до 7 минут.
    5. Не стесняйтесь копировать сценарии, всё-таки код сценария не совсем тоже самое, что код решения. Во многих случаях, лучше не злоупотреблять возможностью организации в тестах изощренных зависимостей ради ухода от повторения кода. Ведь тесты падают и время на анализ “почему?” тоже нужно брать в расчет. При сложных зависимостях, это будет сделать не просто (хотя полный стек ошибок и отладчик в Тестере есть).
    6. При копировании тестов не забывайте менять идентификатор окружения.

    Запустите тест, он должен пройти без ошибок. Этот этап готов, идем дальше.

    Этап 4

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

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

    Программирование Тестирование

    В Конфигураторе: 

    1. Добавляем форму записи в регистр сведений Согласование
    2. Формируем внешний вид
    3. Пишем логику работы формы

    В Тестере

    Создадим тест РедактированиеФормыСогласования, где:

    1. Определим окружение:
      1. Наименование Поставщика
      2. Наименование Покупателя
      3. Товар с датой согласования
    2. Создадим окружение
      1. Создадим поставщика, покупателя и товар
      2. Сделаем поступление
      3. Создадим и проведем реализацию
    3. Целевая часть
      1. Откроем список регистра Согласование
      2. Установим отбор по покупателю и откроем единственную в списке запись
      3. Убедимся, что поле Комментарий недоступно для редактирования
      4. Нажмем галку Отработано, убедимся, что поле Комментарий теперь доступно.
      5. Сохраним и закроем форму
      6. Откроем её еще раз и убедимся, что поле Комментарий доступно
      7. Снимем галку Отработано, затем опять включим и убедимся, что поле Комментарий очищено
      8. Попробуем в списке создать новую запись
      9. Проверим, получил ли пользователь предупреждение о запрете на непосредственный ввод записей в регистр

    Этот рывок будем делать комбинированно. Начнем с создания макета формы, в конфигураторе, создадим такую запись регистра:

    Запустим приложение. Переключимся в Тестер, и в дереве сценариев создадим и зададим как основной тест РедактированиеФормыСогласования:

    И введем такой код:

    // Сценарий:
    // - Создадим окружение в результате которого будет существовать проведенный документ
    //   реализация с товаром, для которого указана дата согласования
    // - Откроем список регистра Согласование
    // - Установим отбор по покупателю и откроем единственную в списке запись
    // - Убедимся, что поле Комментарий недоступно для редактирования (условия задачи были описаны здесь)
    // - Нажмем галку Отработано, убедимся, что поле Комментарий теперь доступно.
    // - Сохраним и закроем форму
    // - Откроем её еще раз и убедимся, что поле Комментарий доступно
    // - Снимем галку Отработано, затем опять включим и убедимся, что поле Комментарий очищено
    // - Попробуем в списке создать новую запись
    // - Проверим, получил ли пользователь предупреждение о запрете на непосредственный ввод записей в регистр
    
    Вызвать ( "Общее.Начало" );
    ЗакрытьВсё ();
    
    ид = "25CB8B15";
    тест = окружение ( ид );
    создатьОкружение ( тест );
    
    // ************************************
    // Целевой сценарий
    // ************************************
    
    // Откроем регистр согласований
    Коммандос ( "e1cib/list/РегистрСведений.Согласование" );
    список = Здесь ( "Согласование" );
    
    // Установим фильтр по покупателю
    покупатель = тест.Покупатель;
    Ввести ( "!КлиентФильтр", покупатель );
    
    // Найдем его в списке
    Кстроке ( "!Список", "Клиент", покупатель );
    
    // Откроем запись
    Нажать ( "!ФормаИзменить" );
    Здесь ( Приложение.ПолучитьАктивноеОкно ().ПолучитьОбъект () );
    
    // Проверим, что с галкой, может с прошлого раза осталась включенной
    если ( "Истина" = Взять ( "!Отработано" ) ) тогда
    	Нажать ( "!Отработано" ); // выключим шалку
    конецесли;
    
    // Комментарий должен быть недоступен
    ПроверитьСтатус ( "!Комментарий", "Доступность", ложь );
    
    // Жмем галку Отработано
    Нажать ( "!Отработано" );
    
    // Комментарий должен быть доступен
    ПроверитьСтатус ( "!Комментарий", "Доступность" );
    
    // Вводим что-то в комментарий
    Установить ( "!Комментарий", "Тестовый комментарий" );
    
    // Нажимаем Записать и закрыть
    Нажать ( "!ФормаЗаписатьИЗакрыть" );
    
    // Возвращаемся в список и опять открываем эту запись
    Здесь ( список );
    Нажать ( "!ФормаИзменить" );
    Здесь ( Приложение.ПолучитьАктивноеОкно ().ПолучитьОбъект () );
    
    // Комментарий должен быть доступен
    ПроверитьСтатус ( "!Комментарий", "Доступность" );
    
    // Снимаем галку Отработано и устанавливаем заново
    Нажать ( "!Отработано" );
    Нажать ( "!Отработано" );
    
    // Комментарий должен быть очищен
    Проверить ( "!Комментарий", "" );
    Нажать ( "!ФормаЗаписатьИЗакрыть" );
    
    // Закроем форму, вернемся в список и попробуем ввести новую запись
    Здесь ( список );
    Нажать ( "!ФормаСоздать" );
    
    // Проверим обязательное наличие сообщения об ошибке
    если ( НайтиСообщения ( "*формируются автоматически*" ).Количество () = 0 ) тогда
        Стоп ( "Отсутствует сообщение об ошибке" );
    конецесли;
    Закрыть ();
    
    // *********************************************
    // Процедуры
    // *********************************************
    
    Функция окружение ( ИД )
    
    	дата = ТекущаяДата ();
    	п = новый Структура ();
    	п.Вставить ( "ИД", ИД );
    	п.Вставить ( "Дата", дата );
    	п.Вставить ( "Согласование", дата + 172800 ); // Через два дня
    	п.Вставить ( "ДатаПоступления", дата - 86400 );
    	п.Вставить ( "Поставщик", "Поставщик " + ИД );
    	п.Вставить ( "Покупатель", "Покупатель " + ИД );
    	п.Вставить ( "Склад", "Склад " + ИД );
    	п.Вставить ( "Товары", определитьТовары ( п ) );
    	возврат п;
    
    КонецФункции
    
    Функция определитьТовары ( Тест )
    
    	ид = Тест.ИД;
    	список = новый Массив ();
    	список.Добавить ( новыйТовар ( "Товар1 " + ид, 15, 250, 350, Тест.Согласование ) );
    	возврат список;
    
    КонецФункции
    
    Функция новыйТовар ( Товар, Количество, Стоимость, Цена, Согласование = неопределено )
    
    	п = новый Структура ();
    	п.Вставить ( "Товар", Товар );
    	п.Вставить ( "Количество", Количество );
    	п.Вставить ( "Стоимость", Стоимость );
    	п.Вставить ( "Цена", Цена );
    	п.Вставить ( "Согласование", Согласование );
    	возврат п;
    
    КонецФункции
    
    Процедура создатьОкружение ( Тест )
    
    	ид = Тест.ИД;
    	
    	// *****************************************************
    	// Проверяем, нужно ли создавать данные для тестирования
    	// *****************************************************
    	
    	если ( СозданоОкружение ( ид ) ) тогда
    		возврат;
    	конецесли;
    	
    	// ******************
    	// Создаем склад
    	// ******************
    	
    	п = Вызвать ( "Справочники.Склады.Создать.Параметры" );
    	п.Наименование = Тест.Склад;
    	Вызвать ( "Справочники.Склады.Создать", п );
    
    	// ******************
    	// Создаем поставщика
    	// ******************
    	
    	п = Вызвать ( "Справочники.Поставщики.Создать.Параметры" );
    	п.Наименование = Тест.Поставщик;
    	Вызвать ( "Справочники.Поставщики.Создать", п );
    
    	// *******************
    	// Создаем покупателей
    	// *******************
    	
    	п = Вызвать ( "Справочники.Покупатели.Создать.Параметры" );
    	п.Наименование = Тест.Покупатель;
    	Вызвать ( "Справочники.Покупатели.Создать", п );
    
    	// **************
    	// Создаем товары
    	// **************
    	
    	для каждого товар из Тест.Товары цикл
    		п = Вызвать ( "Справочники.Номенклатура.Создать.Параметры" );
    		п.Наименование = товар.Товар;
    		Вызвать ( "Справочники.Номенклатура.Создать", п );
    	конеццикла;
    
    	// *******************
    	// Создаем поступление
    	// *******************
    	
    	товары = новый Массив ();
    	для каждого позиция из тест.Товары цикл
    		товар = Вызвать ( "Документы.ПоступлениеТоваровУслуг.Создать.Товар" );
    		товар.Товар = позиция.Товар;
    		товар.Количество = позиция.Количество;
    		товар.Цена = позиция.Стоимость;
    		товары.Добавить ( товар );
    	конеццикла;
    
    	п = Вызвать ( "Документы.ПоступлениеТоваровУслуг.Создать.Параметры" );
    	п.Товары = товары;
    	п.Дата = тест.ДатаПоступления;
    	п.Поставщик = тест.Поставщик;
    	п.Склад = тест.Склад;
    
    	Вызвать ( "Документы.ПоступлениеТоваровУслуг.Создать", п );
    	
    	// *******************
    	// Создаем реализацию
    	// *******************
    	
    	товары = новый Массив ();
    	для каждого позиция из тест.Товары цикл
    		товар = Вызвать ( "Документы.РеализацияТоваровУслуг.Создать.Товар" );
    		товар.Товар = позиция.Товар;
    		товар.Количество = позиция.Количество;
    		товар.Цена = позиция.Цена;
    		товар.Согласование = позиция.Согласование;
    		товары.Добавить ( товар );
    	конеццикла;
    
    	п = Вызвать ( "Документы.РеализацияТоваровУслуг.Создать.Параметры" );
    	п.Товары = товары;
    	п.Дата = тест.Дата;
    	п.Покупатель = тест.Покупатель;
    	п.Склад = тест.Склад;
    
    	Вызвать ( "Документы.РеализацияТоваровУслуг.Создать", п );
    	
    	// ********************************
    	// Регистрируем созданное окружение
    	// ********************************
    	
    	СохранитьОкружение ( ид );
    
    КонецПроцедуры

    Комментарии по коду сценария:

    1. Этот тест был создан путем копирования предыдущего, окружение практически не модифицировалось, я убрал создание потенциального клиента
    2. Может вызвать интерес такая строка кода: Здесь ( Приложение.ПолучитьАктивноеОкно ().ПолучитьОбъект () );. В данном случае показан пример работы с тестируемым приложением через стандартные методы платформы. В переменной Приложение, Тестер хранит объект ТестируемоеПриложение, через который можно вызывать все остальные методы платформы в режиме клиента тестирования (подробнее см. API Тестера).

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

    // *****************************************
    // *********** События формы
    
    &НаСервере
    Процедура ПриЧтенииНаСервере ( ТекущийОбъект )
    	
    	оформить ();
    	
    КонецПроцедуры
    
    &НаСервере
    Процедура оформить ( Зависимость = неопределено )
    	
    	если ( Зависимость = неопределено или есть ( Зависимость, "Отработано" ) ) тогда
    		Элементы.Комментарий.Доступность = Запись.Отработано;
    	конецесли;
    	
    КонецПроцедуры
    
    &НаСервере
    Функция есть ( Зависимость, Список )
    	
    	возврат СтрРазделить ( Список, "," ).Найти ( Зависимость ) <> неопределено;
    	
    КонецФункции
    
    &НаСервере
    Процедура ПриСозданииНаСервере ( Отказ, СтандартнаяОбработка )
    	
    	если ( Запись.ИсходныйКлючЗаписи.Пустой () ) тогда
    		ошибка ();
    		Отказ = истина;
    	конецесли;
    	
    КонецПроцедуры
    
    &НаСервере
    Функция ошибка ()
    	
    	Сообщить ( Нстр ( "ru = 'Записи в данном регистре формируются автоматически, при проведении документа Реализация товаров и услуг'" ) );
    	
    КонецФункции
    
    // *****************************************
    // *********** Группа Форма
    
    &НаКлиенте
    Процедура ОтработаноПриИзменении ( Элемент )
    	
    	применитьОтработано ();
    	оформить ( "Отработано" );
    	
    КонецПроцедуры
    
    &НаКлиенте
    Процедура применитьОтработано ()
    	
    	если ( не Запись.Отработано ) тогда
    		Запись.Комментарий = "";
    	конецесли;
    	
    КонецПроцедуры
    

    Затем, переключимся в форму и зададим обработчики событий: ПриЧтенииНаСервере, ПриСозданииНаСервере, ОтработаноПриИзменении. Запустите приложение, запустите тест и убедитесь, что он проходит.

    Заключение

    Мы рассмотрели теоретическую и практическую части применения системы Тестер для организации работы программиста через тестирование управляемого кодом клиентского приложения. Многие выкладки можно найти спорными и даже прямо противоположными учениям авторитетов в области построения процессов тестирования. Не вопреки, а с осознанием этого, готовился данный материал. Основной целью было показать практическое применение методики и средств сценарного тестирования.

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

    Проверка бизнес логики

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

    Например, при вводе документа Заказ поставщику, все движения, сформированные этим документом попадают под понятие бизнес логика.

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

    1. Можно сформировать отчет о движениях документа и сверить эти движения с эталоном.
    2. Можно сформировать отчет или группу отчетов для анализа последствий изменения данных.

    Оба способа основаны по проверке данных отчетов/печатных форм тестируемого приложения с эталонными данными, хранящимися в самом тесте.

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

    Процессы ниже будут рассмотрены на примере тестирования конфигурации ERP2.

    Подготовка эталона

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

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

    За получением макета мы должны идти в тестируемое приложение. Там, необходимо сформировать отчет о движениях тестируемого документа, скопировать результат в буфер обмена (Ctrl+A, Ctrl+C), затем, переключиться в Тестер и вставить скопированное в разрабатываемый тест, на вкладку Шаблон.

    Результат таких действий показан на картинке ниже (фактически, на картинке показан уже модифицированный вариант шаблона, детали ниже):

    Области проверки

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

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

    Задание областей осуществляется по правому клику в поле табличного документа, на картинке ниже, красной штрих линией выделена проверяемая область:

    Автоподстановки

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

    Например, движения документа могут содержать такие данные как: дата записи, номер и дата документа. Так как документы могут проводиться в разное время, часть этих данных в тестируемом приложении может постоянно меняться.

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

    Они работают следующим образом:

    1. {Заказ поставщику *}. Означает, что в поле должно быть значение, начинающееся с текста “Заказ поставщику”, а дальше не важно
    2. {_Товар1 *}. Тот же смысл, что и в п.1
    3. {*}. Означает, что в данном поле должно быть хоть какое-то значение. Если значения при проверке не окажется – будет вызвано исключение.
    Внимание! Проверка строк не чувствительна к регистру

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

    Формирование скриншотов

    Тестер умеет формировать скриншоты в следующих ситуациях:

    1. Автоматически, при падении теста
    2. По требованию в программном коде, см. метод Снимок
    3. Автоматически, при активации хронографа.

    Для того, чтобы Тестер автоматически формировал снимки экранов, необходимо в справочнике Приложения, найти и открыть интересующее приложение, и заполнить там поле Заголовок приложения. В этом поле задается регулярное выражение, синтаксиса ECMAScript (https://www.regular-expressions.info/).

    На картинке ниже, показана строка для конфигурации ERP2:

    Для конфигурации 1С:Документооборот 8 КОРП, регулярное выражение может быть таким: .+Док.+КОРП.+

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

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

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

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

    Просмотр скриншотов осуществляется из журнала ошибок, или хронографа.

    Внимание! Если снимки не формируются, проверьте, правильно ли задано регулярное выражение для поиска тестируемого приложения. Спецсимволы регулярного выражения грамматики ECMAScript отличаются от символов подстановки, которые используются в методах поиска объектов тестируемого приложения. Подробнее читайте на сайте https://www.regular-expressions.info/. Кроме этого, если снимки формируются в виде черного квадрата, обратите внимание на эту статью Почему скриншот формируется в виде черного квадрата?

    Технические детали: В платформе отсутствует штатная возможность получения снимков экрана, поэтому в Тестере реализована внешняя компонента для таких задач. Установка внешней компоненты происходит при первом запуске Тестера. После успешной установки компоненты, последующие запуски уже не будут требовать её установки. Компонента написана по технологии NativeAPI на C++, работает под операционной системой Windows, не требует дополнительного ПО и лицензий, собрана для x32 и x64 клиентов 1С:Предприятие 8.3.

    Хронограф

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

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

    В интерфейсе Тестера, хронограф может быть открыт из основного меню сценария, или контекстного меню в дереве сценариев:

    А также из контекстного меню журнала ошибок или журнала выполнения:

    При работе с хронографом, следует обращать внимание на следующие особенности:

    1. Снятие скриншотов ресурсоёмкая операция, и может увеличить время прохождения тестов на 10% и более
    2. Скриншоты формируются в соответствии с настройками заголовка тестируемого приложения и опцией качества (см. Формирование скриншотов)
    3. Для кода сценария, выполняемого на сервере, скриншоты не формируются
    4. Запись картинок производится в базу данных тестера. На каждом шаге выполняется серверный вызов. Поэтому, если вы используете метод платформы ПоместитьФайл(ы), убедитесь, что последним параметром вы передаете сформированный ранее идентификатор, хранящейся в некоторой переменной, в модуле сценария. В противном случае, после помещения файла во временное хранилище, данные из него будут неявно удалены еще до выполнения следующей строки кода сценария (см. также Как понять, что послужило зависанию или трудноуловимой ошибке в работе приложения (менеджера или клиента тестирования)?).
    5. При использовании хронографа в процессе исполнения сценариев, захваченных другими пользователями, хронограф использует их (сценариев) последние версии, а не захваченные сценарии. Таким образом, для анализа хода выполнения таких сценариев, необходимо открыть версию сценария, и только затем, хронограф по выбранной версии.

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

    ХронографСтарт ();
    
    //...
    // Выполняются действия сценария
    //...
    
    // Если в сценарии возникнет ошибка, до этого места выполнение не дойдет, ошибка будет
    // зафиксирована стандартным образом. Но если ошибок не будет, код ниже
    // очистит данные хронографа накопленные для этого сценария (не включая подчиненные!)
    ХронографСтоп ();
    ХронографОчистить ( Хронограф.Сценарий );

    Кроме этого, следует отметить, что хронограф создает копии сценариев по версиям в служебном справочнике Modules. Для скорости обработки, метод ХронографОчистить их не удаляет. С течением времени, там может накапливаться большое количество элементов, которое не сказывается на производительности, но увеличивает общий объем базы данных. При необходимости, вы можете помечать на удаление и удалять элементы этого справочника, стандартным образом.

    Выгрузка и загрузка, Git

    Тестер позволяет выгружать и загружать сценарии в файловую систему.

    Поддерживается инкрементальная выгрузка/загрузка.

    Обработки по выгрузке и загрузке доступны в меню быстрых функций, а также через акселераторы Ctrl+Shift+B (выгрузка), Ctrl+Shift+L (загрузка)

    Выгруженные файлы могут быть синхронизированы с системами контроля версий, например Git.

    Для конфигурации ERP2, было создано депо https://github.com/grumagargler/ERP2

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

    Интеграция с Visual Studio Code

    Visual Studio Code (далее vscode) является продвинутым текстовым редактором, возможности которого значительно превосходят возможности встроенного в Тестер редактора модулей. При разработке большого числа сложных тестов, улучшенная эргономика работы с кодом может стать важной составляющей всего процесса написания, анализа и запуска сценариев.

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

    Для работы в интегрированном режиме, оба приложения (Тестер и vscode) должны быть запущены.

    Подготовка Тестера

    Для того, чтобы начать взаимодействовать с vscode, необходимо смонтировать приложение(я) Тестера в папки на диске:

    Затем, необходимо создать запись для монтируемых приложений, например так:

    Внимание! Флаг Маппинг должен быть включен, иначе Тестер не сможет общаться с vscode в автоматическом режиме.

    Если вы монтируете более одного приложения, рекомендуется указывать для них общий начальный путь к папке на диске. Например, на картинке выше, приложение ERP2 и <Общее> имеют общий начальный путь c:\tests\. Такая структура (общий начальный путь) позволяет плагину vscode редактировать и осуществлять переходы к связанным сценариям сразу для всех смонтированных приложений с общей начальной папкой. В противном случае, переходы к связанным сценариям, например, при нажатии F12 на параметре метода Вызвать ( “Общее.Найти” ), будут затруднены.

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

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

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

    На этом этапе, подготовительная работа в Тестере завершена.

    Подготовка Visual Studio Code

    Необходимо скачать и установить vscode. Страница для скачивания: https://code.visualstudio.com/

    Внимание! если вы скачали 32-битную версию или установили vscode в директорию, отличную от C:\Program Files\Microsoft VS Code, тогда укажите в Тестере, в форме настройки компьютера, путь к запускаемому файлу vscode, как показано на рисунках ниже

    Работа в vscode

    На данном этапе все настройки завершены, теперь можно редактировать и запускать сценарии из vscode.

    На примере демо-базы это будет выглядеть так:

    После этого, запустится vscode и предложит вам установить плагин, как показано на картинке ниже:

    Нажмите на указанную кнопку и установите предлагаемый плагин:

    После того, как расширение Tester 1C будет установлено (вместе с ним, будет установлено расширение xDrivenDevelopment.language-1c-bsl от специалистов команды xDrivenDevelopment, за что им отдельная благодарность), необходимо перезагрузить редактор:

    На этом настройка завершена, можно начинать работу.

    На момент написания статьи, плагин vscode поддерживает следующие операции:

    1. Интеллисенс всех функций тестера на двух языках (справка пока только на русском). Навигация к сценариям, заданным в методах Вызвать () и Позвать ().
    2. Считывание полей тестируемого приложения в процесса набора параметра функции с фильтрацией по типу. Примечание: тестируемое приложение при этом должно быть запущено
    3. Запуск теста, кнопка F5
    4. Запуск выделенного фрагмента кода, комбинация ctrl+alt+R
    5. Синтаксический контроль, комбинация ctrl+F7
    6. Вывод диагностических сообщений в панель Output (см. метод ВСтудию()/VStudio())
    7. Вывод сообщений об ошибках в панель Problems
    8. Назначение основного сценария (кнопка F1 / Set Main)
    9. Сниппеты. При наборе тест плагин выдаст все допустимые методы Тестера

    Другие полезные комбинации клавиш:

    ctrl + E. Открывает окно нечеткого поиска сценария для его открытия в новой вкладке.

    ctrl + shift + E. Активация дерева файлов проекта.

    alt + F12. Открытие в сплывающем окне модуля процедуры, функции или сценария. Удобно использовать для беглого просмотра когда связанного сценария.

    ctrl + shift + O. Быстрый переход к процедуре/функции кода сценария.

    ctrl + shift + F, ctrl + shift + H. Глобальный поиск и глобальная замена. Важной способностью этих функций является возможность указания начальной папки (поле чувствительно к регистру) поиска/замены. 

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

    Полезные приемы работы

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

    Механизм заданий

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

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

    1. Тестирование по расписанию. Например, можно составить расписание для еженочного запуска тестирования.
    2. Прогон тестов разных веток/версий конфигурации с формированием сборок в рамках методики непрерывной интеграции.
    3. Запуск тестов в процессе разработки. Например, программист в процессе кодирования, может создать задачу на выполнение ряда тестов на виртуальной машине. Такой делегированный процесс не будет отвлекать его от текущего процесса разработки, а последующий анализ прохождения тестов по заданию, даст специалисту понимание, как повлияли его последние изменения на работу программы.
    4. Запуск тестирования по событию. Например, можно разработать сценарий, алгоритм которого будет автоматически запускать процесс тестирования при изменении версии конфигурации.
    5. Выполнение регламентных операций в продуктивных базах. Например, можно разработать сценарий, который будет взаимодействовать с приложением в режиме пользователя, и выполнять определенную рутину (удаление помеченных, запуск проведений, формирование и рассылка отчетов, курсов валют, и так далее).

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

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

    Права

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

    (см. Меню / Пользователи).

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

    Чтобы пользователь стал агентом, необходимо в его профиле установить признак Агент:

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

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

    Создание

    Задание может быть создано несколькими способами:

    1. Непосредственно через журнал Меню / Задания
    2. Через подменю Запустить на верхней панели окна редактирования сценария
    3. Через контекстное меню в дереве сценариев

    Пример создания задания из формы редактирования сценария:

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

    1. Агент и Компьютер. В связи с тем, что один и тот же агент может быть запущен на разных компьютерах, в задании можно указать, для какого компьютера оно должно выполняться. Если компьютер задан не будет, задание будет выполнено первым свободным компьютером с запущенной на нем сессией указанного агента.
    2. Если в качестве варианта запуска задания будет указано расписание, тогда следует дополнительно обратить внимание на флаг Игнорировать завершение. По умолчанию, данный флаг выключен. Это означает, что Тестер не будет формировать очередное задание, пока предыдущее не будет выполнено. Если флаг будет включён, Тестер будет создавать и ставить в очередь задания, несмотря на факт их выполнения.
    3. Последовательность сценариев в таблице будет соблюдаться при их запуске. Если в таблице указан сценарий, который на момент запуска редактируется, или этот сценарий вызывает другие сценарии, которые в свою очередь находятся в режиме редактирования, агент будет получать их последние версии (по сценариям ведется версионирование). Таким образом, если требуется запуск сценариев с последними изменениями, их нужно предварительно поместить в хранилище.

    Изменение

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

    Создание заданий через rest-сервис

    Некоторые сценарии требуют взаимосвязь разнородных информационных систем. Для предоставления интерфейса по формированию заданий, в Тестере реализован rest-сервис Job. С его помощью, внешняя среда может формировать Тестеру задания с передачей необходимых параметров.

    Например, стоит задача протестировать получение заказов через веб-магазин (обычный сайт на php), и загрузку этих данных в прикладное решение Управление Торговлей (УТ). При этом, нужно протестировать как работу API сайта, так и механизм загрузки данных в УТ. В упрощенном виде, такой сценарий должен вначале загрузить данные на сайт используя его Rest API (способы тестирования веб-сайтов выходят за рамки этой документации), а затем, дать задание Тестеру на запуск тестирования механизма загрузки данных прикладного решения.

    Инфраструктура со стороны Тестера должна выглядеть таким образом:

    1. Информационная база с Тестером публикуется на веб-сервере для возможности вызова его rest-сервиса. Подробнее о публикации, читайте в официальной документации.
    2. В тестовом окружении, должен быть запущен менеджер тестирования под агентом-пользователем, который фактически и будет выполнять сценарное тестирование.

    Весь цикл будет примерно таким:

    1. Используя специальный фреймворк или собственную разработку, front-end разработчик, эмулируя действия пользователя, выполняет наполнение данными тестируемый веб-сайт.
    2. Затем, его сценарий (на php или любом другом языке) вызывает rest-сервис Тестера и просит его выполнить сценарий уже в контексте сценарного тестирования 1С. Выполняя POST-запрос, веб-разработчик указывает идентификатор сценария, приложение и агента.
    3. Rest-сервис Тестера, создаст в информационной базе задание на тестирование. Тут важно отметить, что сервис не запускает сценарий на выполнение, а лишь формирует задание и ставит его в очередь.
    4. Выполнение сценариев осуществляется “на клиенте”, на тестовом сервере, отдельно запущенной сессией менеджера тестирования (в той же информационной базе) под пользователем-агентом. Эта сессия будет выполнять задания из очереди.
    5. По окончании тестирования в Тестере, код сценария может выполнить http-запрос на продолжение/уведомление инфраструктуры тестового окружения веб-сайта.

    Пример вызова POST-запроса на создание задания. Код приведен на языке 1С, но может быть легко адаптирован под php, javascript или другой язык:

    // Адрес опубликованного Тестера на веб-сервере, где:
    //  localhost: имя или IP-адрес хоста
    //  tester: имя опубликованного приложения
    address = "localhost/tester";
    
    // Имя и пароль пользователя в Тестере, который имеет
    // право создавать задания. Например, это может быть
    // ваш профиль, под которым вы работаете в Тестере
    user = "Разработчик";
    pswd = "0123456";
    
    connection = new HTTPConnection ( address + "/hs", , user, pswd );
    
    // Так называется rest-сервис
    request = new HTTPRequest ( "/Job" );
    
    // Структура параметров, которая будет преобразована в JSON
    // {
    // "Agent": null,
    // "Scenario": null,
    // "Application": null,
    // "Parameters": null,
    // "Computer": null,
    // "Memo": null
    // }
    params = new Structure ( "Agent, Scenario, Application, Parameters, Computer, Memo" );
    
    // Имя пользователя-агента, который будет выполнять сценарий на клиенте.
    // Его сессия должна быть запущена.
    params.Agent = "animal";
    
    // Идентификатор сценария в базе тестов Тестера
    params.Scenario = "Документы.ЗаказПокупателя.ЗагрузкаСВеб";
    
    // Тестируемое приложение
    params.Application = "УТ";
    
    // Параметры, которые можно передать заданию.
    // Пример доступа к этим параметрам из кода сценария см. ниже
    params.Parameters = new Structure ( "Параметр1", "Значение параметра 1" );
    
    // Произвольные заметки
    params.Memo = "Это моё задание";
    
    request.SetBodyFromString ( Conversion.ToJSON ( params ) );
    connection.Post ( request );

    Для доступа к параметрам на уровне сценария Документы.ЗаказПокупателя.ЗагрузкаСВеб, можно использовать следующий код:

    // Получаем ссылку на задание из служебной переменной Debug
    задание = Debug.Job.Job;
    
    // Получаем параметры, они там находятся в строке JSON
    данные = DF.Pick ( задание, "Parameters" );
    
    // Преобразуем их в структуру
    параметры = Conversion.FromJSON ( данные );
    
    // Вывод результата
    Сообщить ( параметры.Параметр1 );

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

    Пример вызова get-запроса уже из самого кода сценария в Тестере. Пример не выполняет полезных действий с точки зрения логики сценария, но демонстрирует возможность коммуникации сценария с внешней средой:

    подключение = новый HTTPСоединение ( "httpbin.org" );
    запрос = новый HTTPЗапрос ( "/ip" );
    результат = подключение.Получить ( запрос );
    статус = результат.StatusCode;
    если ( статус = 200 ) тогда
    	данные = Conversion.FromJSON ( результат.ПолучитьТелоКакСтроку () );
    	Сообщить ( "Ваш IP: " + данные.Origin );
    иначе
    	Стоп ( "Ошибка, статус возврата: " + статус );
    конецесли;

    Вместо получения IP-адреса, вы можете сообщить об успехе выполнения теста.

    Запуск тестов по расписанию

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

    Задачу тестирования по расписанию можно разложить на три составляющие:

    1. Безопасность
    2. Подготовка базы для тестирования
    3. Запуск тестирования

    Безопасность

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

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

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

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

    Подготовка базы для тестирования

    Подготовка базы для тестирования производится на серверной части и состоит из двух этапов:

    1. Загрузка начальной базы данных (подробнее о начальной базе см. здесь)
    2. Обновление начальной базы данных актуальными изменениями в конфигурации

    Для автоматизации этих операций рекомендую использовать командные cmd-файлы.

    worker.cmd

    Первый файл будет называться worker.cmd. Он будет служить в качестве “процедуры”, в которую мы будем передавать параметры. Расположите этот файл в некоторой общей папке, например c:\testing.

    Вот содержимое worker.cmd:

    set _1c="C:\Program Files (x86)\1cv8\%1\bin\1cv8.exe"
    set ibname=%2
    set ibuser=%3
    set ibpswd=%4
    set initdb=%5
    set repouser=%6
    set repopswd=%7
    set repoaddr=%8
    
    
    %_1C% designer /IBname %ibname% /N %ibuser% /p %ibpswd% /DisableStartupMessages /RestoreIB %initdb% /ConfigurationRepositoryN %repouser% /ConfigurationRepositoryP %repopswd% /ConfigurationRepositoryF %repoaddr%
    %_1C% designer /IBname %ibname% /N %ibuser% /p %ibpswd% /DisableStartupMessages /ConfigurationRepositoryUpdateCfg -force /ConfigurationRepositoryN %repouser% /ConfigurationRepositoryP %repopswd% /ConfigurationRepositoryF %repoaddr%
    %_1C% designer /IBname %ibname% /N %ibuser% /p %ibpswd% /DisableStartupMessages /UpdateDBCfg /ConfigurationRepositoryN %repouser% /ConfigurationRepositoryP %repopswd% /ConfigurationRepositoryF %repoaddr%
    

    Где:

    Параметр Описание
    1CVersion

    Версия 1С:Предприятие.

    Например: 8.3.10.2252 (без кавычек)

    IBName

    Имя базы в списке информационных баз стартера 1С.

    Например: “Бухгалтерия предприятия КОРП (демо)”

    user Имя пользователя в начальной базе. Этот пользователь должен обладать административными правами в информационной базе
    password Пароль пользователя в начальной базе
    DTFile

    Путь к файлу-выгрузке с начальной базой. Файл с расширением dt.

    Важно! Выгрузка начальной базы не должна быть подключена к  хранилищу конфигурации. Перед созданием dt-файла, отключите конфигурацию от хранилища 1С.
    repouser Имя пользователя в хранилище конфигурации 1С, откуда будут получены последние изменения конфигурации. Предварительно, создайте специального для целей тестирования пользователя.
    repopassword Пароль пользователя в хранилище конфигурации 1С
    reposerver/reponame

    Путь к хранилищу конфигурации с указанием названия приложения.

    Например: tcp://repositoryserver/myapplication

    или

    tcp://repositoryserver:1641/myapplication

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

    prepare.cmd

    Далее, необходимо создать еще один скрипт, который будет запускать worker.cmd и передавать ему нужные параметры.

    Назовем этот скрипт prepare.cmd, содержимое будет таким:

    rem chcp 1251 >nul
    
    c:\testing\worker.cmd 8.3.10.2252 "MyApplication" admin 123456 "C:\Users\Administrator\Desktop\MyApplication\init.dt" tester 654321 "tcp://server/myapplication"

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

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

    Запуск сервера 1С

    Несколько слов о запуске сервера 1С:Предприятие. Я рекомендую на серверной части тестовой среды ставить сервер приложений как обычное приложение, а не как сервис. Используйте ярлык запуска ragent.exe (установщик платформы создает такие ярлыки автоматически), скопируйте его в общую папку c:\testing. Так, у вас будет возможность тестировать приложения разных версий, без того, чтобы использовать специальные средства размещения сервисов разных версий. Очевидно, что сервер приложений должен быть запущен заранее.

    Планирование запуска

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

    Это задание должно запуститься и выполниться раньше, чем клиентская часть тестирования начнет прогон сценариев. Поэтому время запуска задание запланируйте на час раньше времени запуска задания в клиентской части среды тестирования. При решении этой задачи, можно использовать два подхода: (рекомендованный) механизм заданий или планировщик операционной системы. Для полноты картины, в этом параграфе приведен пример с системным планировщиком.

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

    Итог

    Подытожу описанные знания краткой последовательностью действий:

    1. Создаем папку c:\testing
    2. Создаем там файл worker.cmd
    3. Опционально: размещаем ярлык запуска сервера 1С как приложения, с нужной версией сервера 1С. Запускаем сервер 1С
    4. Создаем еще одну папку, под тестируемую конфигурацию, например c:\Users\Administrator\Desktop\MyApplication
    5. В эту папку кладем:
      1. Скрипт prepare.cmd
      2. Файл выгрузки init.dt
    6. Используя Механизм заданий или планировщик операционной системы, создаем задачу по расписанию и пускаем её за час до начала прогона сценариев.

    Переходим к настройке клиентской части окружения тестовой среды.

    Запуск тестирования

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

    Запуск тестов по расписанию возможен за счет механизма заданий или настройки планировщика запуска программ средствами операционной системы.

    Например, в операционной системе Windows, для этого можно воспользоваться программой Планировщик задач.

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

    "C:\Program Files (x86)\1cv8\8.3.8.2088\bin\1CV8C.exe" /IBName"Тестер" /N"Администратор" /C"ЗапуститьERP2тесты" /TESTMANAGER

    Где:

    C:\Program Files (x86)\1cv8\8.3.8.2088\bin\1CV8C.exe путь к запускаемой версии платформы
    /IBName"Тестер" название информационной базы в списке информационных баз
    /N"Администратор" имя пользователя (используйте /P если нужно задать пароль)
    /C"ЗапуститьERP2тесты"

    путь к запускаемому сценарию. Также, есть возможность явного указания приложения, в таком формате: /C"ERP2#ЗапуститьERP2тесты"

    Пример:

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

    // Запуск клиента тестирования
    команда = """C:\Program Files (x86)\1cv8\8.3.8.2088\bin\1CV8C.exe"" /S""localhost\erp2"" /N""Бухлалтер"" /TESTCLIENT";
    ЗапуститьПриложение ( команда );
    
    // Ждем 5 секунд, пока запустится
    Пауза ( 5 );
    
    // И дальше пошли выполнять тесты
    Подключить ();
    
    // и т.д.

    Более полный пример сценарного теста, который запускает все остальные тесты смотрите в демонстрационной базе, тест называется ЗапуститьERP2тесты, либо на github по ссылке: https://github.com/grumagargler/ERP2/blob/master/%D0%97%D0%B0%D0%BF%D1%83%D1%81%D1%82%D0%B8%D1%82%D1%8CERP2%D1%82%D0%B5%D1%81%D1%82%D1%8B.1c.bsl

    Тестирование веб-клиента

    Для тестирования веб-клиента необходимо произвести следующие настройки:

    1. В параметрах запуска приложения, укажите идентификатор веб-приложения:

      В качестве идентификатора приложения может выступать любая строка, удовлетворяющая правилам именования идентификаторов в платформе 1С. Идентификатор является ключом, по которому будет определяться тестируемое приложение в процессе подключения к нему Тестера.
      Примечание: если вы не хотите запускать тестируемый веб-клиент в режиме отладки, добавьте в адресную строку веб-приложения следующие параметры:

      Где идентификатор приложения, указан как Test (см.картинку).
    2. В Тестере, откройте настройку тестируемого приложения и укажите следующие параметры:

    3. Обратите внимание, что в качестве значения порта нужно указать порт сервера 1С:Предприятие (не порт веб-сервера, конфигуратора или какой-то другой). Таким образом, убедитесь, что компьютер, на котором производится тестирование (на котором запущен веб-клиент и Тестер), может обращаться к компьютеру и порту, на котором работает сервер 1С. На картинке, указан стандартный порт сервера 1С, 1541, если у вас он другой – установите актуальное в ваших условиях значение.
    4. Сохраните данные, на этом настройка для тестирования завершена. Теперь вы можете запустить веб-клиент, переключиться на необходимый для тестирования тест и проверить его работоспособность.

    В случае тестирования веб-клиента, Тестер не подключается напрямую к вкладке браузера, всё взаимодействие происходит через сервер 1С:Предприятие. Сервер 1С выступает в качестве “клиента-тестирования” и принимает команды от Тестера. Веб-приложение, опрашивает сервер 1С и если там есть команды для выполнения – они начинают выполняться в браузере. Таким образом, сервер 1С в данной схеме является чем-то на подобии “прокси". Состыковка Тестера и конкретного приложения на вкладке браузера достигается за счет сопоставления идентификатора приложения. В описанном примере идентификатор называется Test, но вы можете изменить его на более подходящий. Используя разные идентификаторы, можно тестировать несколько веб-приложений одновременно.

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

    Описанное выше касается клиент-серверного варианта работы приложения. Для тестирования файлового варианта, используется конфигурационный файл testcfg.xml описание которого можно найти на сайте https://its.1c.ru/db/v8310doc#bookmark:adm:TI000000419.

    Частые вопросы: Тестирование приложения

    Почему выдаются ошибки при воспроизведении ранее записанного сценария через «микрофончик»?

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

    Однако, с практической точки зрения, реальные сценарии не пишутся прокликиванием (записью действий). Человек не в состоянии стабильно и безошибочно, накликать последовательность из 30+ шагов. Кроме этого, такие «накликанные» сценарии получаются очень громоздкими, потому что включают в себя много служебной информации и действий, не имеющих практического смысла с точки действий пользователя.

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

    Как открыть внешнюю обработку или обратиться к меню Файл / Открыть?

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

    Возможны следующие варианты решения проблемы.

    Вариант 1.

    Использование промежуточной, внешней обработки.

    Алгоритм действий следующий:

    1. В Тестере, в Меню быстрые функции / Скачать Worker.epf, скачиваем обработку Worker.epf
    2. В тестируемом приложении, открываем эту обработку, вручную
    3. В Тестере, для открытия целевых внешних обработок, используем тест Тестер.ОткрытьОбработку (тест находится в репозитории общих тестов по ссылке https://github.com/grumagargler/CommonTests). Как загружать тесты, см. здесь.

    Пример использования:

    Подключить ();
    ЗакрытьВсё ();
    
    // Открываем внешнюю обработку
    путь = "c:\ПечатьДокументаЗаказПокупателя.epf";
    Вызвать ( "Тестер.ОткрытьОбработку", путь );
    Обратите внимание, метод ЗакрытьВсё закроет всё, но обработку Worker.epf оставит открытой.
    Таким образом, достаточно Worker.epf открыть лишь однажды, и продолжить разработку
    целевой обработки без необходимости постоянной загрузки промежуточной обработки Worker.epf.

    Вариант 2.

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

    Вариант 3.

    Написать сценарий, который будет запускать тестируемое приложение с указанием обработки запуска.

    Для этой цели можно использовать общий тест Тестер.Запустить, см. пример:

    п = Вызвать ( "Тестер.Запустить.Параметры" );
    п.Пользователь = "Администратор (ОрловАВ)";
    п.База = "ERP Управление предприятием 2 (демо)";
    п.Обработка = "C:\Users\Dmitry\Desktop\МояОбработка.epf";
    Вызвать ( "Тестер.Запустить", п ); // Окно безопасности будет подавлено

    Как при пометке на удаление элемента из формы списка определить, что элемент уже помечен на удаление?

    // По тексту в диалоге определяем, помечается элемент или снимается пометка
    этоУдаление = Найти ( Получить ( "!Поле1", "1?:*" ).ТекстЗаголовка, "Пометить" ) = 1;
    если ( этоУдаление ) тогда
        Нажать ( "Да", "1?:*" );
    иначе
        // Элемент уже помечен на удаление
    конецесли;

    Как нажать на кнопку Открыть?

    Здесь ( "Заказ клиента ДС*" );
    
    // Первый способ
    Получить ( "#Партнер" ).Открыть ();
    
    // Второй способ
    Получить ( "Основное / Клиент" ).Открыть ();
    

    Как нажать на кнопку Создать?

    Здесь ( "Заказ клиента ДС*" );
    
    партнер = Фокус ( "#Партнер" );
    партнер.Создать ();

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

    Здесь ( "Заказ клиента ДС*" );
    
    партнер = Фокус ( "#Партнер" );
    партнер.ОткрытьВыпадающийСписок ();
    партнер.Создать ();

    Как установить значение поля-переключателя (радиобаттона)?

    Для того, чтобы изменить значение такого поля:

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

    // Вариант 1
    Установить ( "Gender", "Female" );
    
    // Вариант 2
    Установить ( "!Sex", "Female" ); // Sex в данном случае является именем реквизита формы

    Еще один пример, конфигурация УТ11, справочник Склады и магазины:

    Оптовый склад можно установить следующим кодом:

    Установить ( "!ТипСкладаОптовый", "Оптовый склад" );

    Пример для конфигурации Розница 2.2:

    Установить ( "!ПереключательТиповПО", 1 );

    Как быстро проанализировать оптимальность проделанных в программе изменений?

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

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

    Как выбрать из меню, которое формируется программно, методом ПоказатьВыборИзМеню или ПоказатьВыборИзСписка?

    Для этой задачи нужно использовать метод тестируемой формы ВыполнитьВыборИзМеню () / ВыполнитьВыборИзСписка ().

    Пример:

    Здесь ( "Документы" );
    Нажать ( "!ФормаСоздатьДокумент" );
    ТекущийОбъект.ВыполнитьВыборИзМеню ( "Создать документ" );
    
    // Или в случае выбора из списка:
    // ТекущийОбъект.ВыполнитьВыборИзСписка ( "Создать документ" );

      Как перейти к строке таблицы по значениям нескольких колонок?

      Допустим, у вас есть такой список:

      И требуется в нем перейти к строке с клиентом “Инвема”  и “% оплаты” = 100%. Для решения этой задачи нужно использовать метод ПерейтиКСтроке объекта ТестируемаяТаблицаФормы.

      Пример:

      Здесь ( "Заказы клиентов" );
      
      список = Получить ( "!Список" );
      список.ПерейтиКПервойСтроке (); // Хотим найти строку начиная с начала списка
      
      поиск = новый Соответствие ();
      поиск.Вставить ( "Клиент", "Инвема" ); // Клиент - название колонки, Инвема - искомое значение
      поиск.Вставить ( "% оплаты", "100" );
      
      перешли = список.ПерейтиКСтроке ( поиск );
      если ( не перешли ) тогда
      	вызватьисключение "Не удалось перейти к заказу";
      конецесли;
      
      // Важно:
      // Искомые значения должны быть в точности такими, как в таблице.
      // Например "100.00" в колонке "% оплаты" найдено не будет.
      // Учитывайте эти особенности, особенно когда работаете с разными форматами дат и чисел

      Подробнее о методах объекта ТестируемаяТаблицаФормы смотрите в синтаксис помощнике конфигуратора.

      Как проверить результат проведения документа?

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

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

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

      Техника работы с шаблонами и тестированием бизнес-логики описана здесь.

      Для получения определенности тестирования, нужна правильная архитектура сценария и настроенное окружение. Подробнее см. Внедрение / Структура сценария.

      Как определить количество строк в таблице?

      Для этого можно использовать тест-метод Таблица.Количество, пример работы с которым показан ниже:

      таблица = Получить ( "!Товары" );
      количество = Вызвать ( "Таблица.Количество", таблица );
      если ( количество = 0 ) тогда
      	Стоп ( "Таблица товаров пустая!" );
      конецесли;

      Данный тест-метод находится в поставляемой с Тестером демонстрационной базе.

      Почему переход к строке таблицы не всегда заканчивается успешно?

      Такое может происходить в случае поиска строки в связанной таблице. Например, вы переходите к строке в Таблица 2, но Таблица 2 зависит от Таблица 1. При этом зависимость определяется в процедуре ПриАктивацииСтроки, Таблица 1, через использование отложенной процедуры заполнения (ПодключитьОбработчикОжидания) второй таблицы.

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

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

      Кстроке ( "!Таблица1", "Клиент", "ТОО Ромашка" );
      Пауза ( 1 ); // подождем, пока сформируются записи во второй таблице
      Кстроке ( "!Таблица2", "Товар", "Датчик давления" );

      Как выбрать значение в поле с составным типом?

      Допустим у вас есть форма и на ней реквизит Документ, тип которого составной:

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

      форма = Здесь ( "Моя форма" ); // Измените на заголовок вашей формы
      
      // Выбираем документ
      Выбрать ( "!Документ" );
      
      // Фокусируемся на окне выбора типа данных
      Здесь ( "Выбор типа данных" );
      
      // Выберем нужным нам тип
      КСтроке ( "!TypeTree", "", "Заказ на перемещение" );
      Нажать ( "!OK" );
      
      // Откроется форма списка, сфокусируемся на ней
      Здесь ( "Заказы на перемещение товаров" );
      
      // Выберем нужный нам документ
      КСтроке ( "!Список", "Номер", "ТД00-000008" );
      Нажать ( "!ФормаВыбрать" );
      
      // Вернемся к нашей изначальной форме
      Здесь ( форма );

      Как нажать на ссылку в навигационной панели формы?

      Допустим, у вас стоит задача нажать на ссылку в навигационной панели формы, как показано на картинке:

      Для решения этой задачи можно применить следующий код:

      Здесь ( "Строка заявки *" );
      
      Нажать ( "Схема", ПолучитьСсылки () );

      Подробнее о методе ПолучитьСсылки () читайте здесь.

      Как сверить отчет со справочником?

      Допустим, у вас стоит задача сверить два объекта.

      Предположим, первым объектом будет отчет по остаткам товаров, вторым – справочник Номенклатура.

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

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

      Подключить ();
      ЗакрытьВсё ();
      
      // Открываем справочник
      Коммандос ( "e1cib/list/Справочник.Номенклатура" );
      товары = Здесь ( "Номенклатура" );
      // Динамический список. Если в ваших условиях он другой
      // тогда просмотрите тестером структуру таблиц формы списка и укажите нужную
      список = Получить ( "!СписокРасширенныйПоискНоменклатура" );
      
      // Открываем отчет и формируем его
      Коммандос ( "e1cib/app/Отчет.ОстаткиИДоступностьТоваров" );
      отчет = Здесь ( "Остатки и дост*" );
      Нажать ( "Сформировать" );
      Пауза ( 5 );
      
      // Определяем параметры и начинаем сверять отчет по справочником
      отчет = Здесь ( "Остатки и дост*" );
      табдок = Получить ( "!ОтчетТабличныйДокумент" );
      строка = 9; // первая значимая строка отчета
      колонкаТовар = 2;
      колонкаИтого = 1;
      колонкаАртикул = 1;
      // Якорь отчета
      конец = "Итого";
      // Если 5 раз товар пустой - выйдем из цикла, чтобы тест не выполнялся бесконечно
      естьТовар = 5;
      пока ( естьТовар ) цикл
      	адрес = "!ОтчетТабличныйДокумент[R" + Формат ( строка, "NG=" ) + "C";
      	ячейкаТовар = адрес + колонкаТовар + "]";
      	товар = Взять ( ячейкаТовар );
      	если ( товар = "" ) тогда
      		ячейкаИтого = адрес + колонкаИтого + "]";
      		если ( конец = Взять ( ячейкаИтого ) ) тогда
      			прервать;
      		конецесли;
      		естьТовар = естьТовар - 1;
      	иначе
      		перешли = КСтроке ( список, "Наименование", товар );
      		если ( перешли ) тогда
      			артикулВОтчете = Взять ( адрес + колонкаАртикул + "]" );
      			// Артикул определяется по идентификатору колонки. В вашем случае, если используется
      			// другая таблица, идентификатор может быть другой. Анализируйте тестером.
      			артикулВСправочнике = Взять ( "!СписокРасширенныйПоискНоменклатураАртикул", список );
      			если ( артикулВОтчете <> артикулВСправочнике ) тогда
      				Стоп ( "Артикул в отчете для товара " + товар + " не совпадает со справочником" );
      			конецесли;
      		иначе
      			Стоп ( "В отчете товар " + товар + " есть, а в справочнике нет" );
      		конецесли;
      		естьТовар = 5;
      	конецесли;
      	Сообщить ( товар );
      	строка = строка + 1;
      конеццикла;
      если ( не естьТовар ) тогда
      	Стоп ( "Не смогли определить конец отчета!" );
      конецесли;

      Как тестировать одновременно несколько запущенных приложений под разными пользователями?

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

      Эту задачу можно решить несколькими способами:

      1. Запускать и тестировать приложение(я) одно за другим
      2. Запустить сразу нужное количество приложений, и затем, переключаясь между ними, выполнять нужные сценарии

      Оба случая основываются на запуске тестируемого приложения из Тестера, для этого можно воспользоваться общим сценарием, входящим в состав общих тестов (https://github.com/grumagargler/CommonTests), следующим образом:

      // ***************************************
      // Запуск 1С в режиме клиента тестирования
      // ***************************************
      
      // Определяем параметры запуска
      п = Вызвать ( "Тестер.Запустить.Параметры" );
      // Название ИБ в списке информационных баз 1С-стартера
      п.База = "ERP Управление предприятием 2 (демо)";
      // Пользователь ИБ
      п.Пользователь = "Администратор (ОрловАВ)";
      // Порт, на котором будет принимать команды тестируемое приложение
      п.Порт = 1538;
      // Другие параметры, при необходимости
      п.Параметры = "/LRU"; // Язык интерфейса
      // Максимальное время ожидания запуска. Если приложение запуститься быстрее
      // тест сразу же будет продолжен, не дожидаясь окончания 30 секунд.
      п.Ждать = 45;
      // Запускаем приложение
      Вызвать ( "Тестер.Запустить", п );
      
      // ********************************************
      // Подключение Тестера к запущенному приложению
      // ********************************************
      
      // Подключаемся к порту 1538, там нас ждут
      Подключить ( , 1538 );
      // Эта команда уже будет выполнена в контексте запущенного на 1538 порту приложения
      ЗакрытьВсё ();

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

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

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

      // Порты запуска приложений
      портЕРП = 1538;
      портБух = 1539;
      
      // Мы хотим, чтобы Тестер фотографировал ошибки каждого приложения
      // даже если их окна будут перекрывать друг друга. Маска поиска задается
      // регулярным выражением. Поиск производится по заголовку главного окна
      скриншотыЕРП = "Демонстрационная база / 1С:ERP.+";
      скриншотыБух = "Демонстрационная база / Абдулов.+";
      
      // ******************
      // Запуск ERP
      // ******************
      
      п = Вызвать ( "Тестер.Запустить.Параметры" );
      п.База = "ERP Управление предприятием 2 (демо)";
      п.Пользователь = "Администратор (ОрловАВ)";
      п.Порт = портЕРП;
      п.Параметры = "/LRU"; // Язык интерфейса
      п.Ждать = 45;
      Вызвать ( "Тестер.Запустить", п );
      
      // ********************
      // Запуск Бухгалтерии
      // ********************
      
      п.База = "Бухгалтерия предприятия КОРП (демо)";
      п.Пользователь = "Абдулов (директор)";
      п.Порт = портБух; // Другой порт
      Вызвать ( "Тестер.Запустить", п );
      
      // ***********************************
      // Работаем с запущенными приложениями
      // ***********************************
      
      // Системный параметр, задает маску поиска приложения по его заголовку
      ScreenshotsLocator = скриншотыЕРП;
      
      // Закроем окна в ЕРП
      Подключить ( , портЕРП );
      ЗакрытьВсё ();
      Отключить ();
      
      // Закроем окна в Бухгалтерии
      ScreenshotsLocator = скриншотыБух;
      Подключить ( , портБух );
      ЗакрытьВсё ();
      Отключить ();
      
      // Откроем в ЕРП справочник номенклатура
      ScreenshotsLocator = скриншотыЕрп;
      Подключить ( , портЕРП );
      Коммандос ( "e1cib/list/Справочник.Номенклатура" );
      
      // Делаем что-то еще
      // .....
      
      // ***********************
      // Закрываем приложения
      // ***********************
      
      Подключить ( , портЕРП );
      Отключить ( истина ); // Параметр истина - приложение будет закрыто
      
      Подключить ( , портБух );
      Отключить ( истина );

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

      Как открыть записи регистра с отбором по регистратору?

      Для решения этой задачи можно воспользоваться общим тестом Общее.Найти.

      В примере ниже, открывается список регистра накопления, и устанавливается отбор по номеру документа:

      Подключить ();
      ЗакрытьВсё ();
      
      Коммандос ( "e1cib/list/РегистрНакопления.НДСЗаписиКнигиПокупок" );
      Здесь ( "НДС Покупки" );
      
      п = Вызвать ( "Общее.Найти.Параметры" );
      п.Где = "Регистратор";
      п.Что = "ТД00-000043"; // Номер документа. Предварительно, может быть получен методом Взять ()
      п.Кнопка = "#ФормаНайти";
      п.Как = 0; // По началу строки
      
      Вызвать ( "Общее.Найти", п );

      Полученные таким образом данные, можно выгрузить в табличный документ и сверить с сохраненным в Тестере шаблоном.

      Как выполнить запрос к базе данных тестируемого приложения?

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

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

      конектор = новый COMОбъект ( "V83.COMConnector" );
      база = "File='C:\Users\Dmitry\Documents\1C\DemoEnterprise20'";
      //база = "Srvr='localhost';Ref='DemoEnterprise20'"; // для базы на сервере
      пользователь = "Администратор (ОрловАВ)";
      соединение = конектор.Connect ( база + ";Usr='" + пользователь + "'" );
      источник = соединение.NewObject ( "Запрос" );
      источник.Text = "
      |выбрать Записи.СуммаБезНДС как Сумма, Записи.НДС как НДС
      |из РегистрНакопления.НДСЗаписиКнигиПродаж как Записи
      |где Записи.Регистратор ссылка Документ.РеализацияТоваровУслуг
      |и выразить ( Записи.Регистратор как Документ.РеализацияТоваровУслуг ).Номер = &Номер
      |";
      номер = "ДС00-000002";
      источник.УстановитьПараметр ( "Номер", номер );
      данные = источник.Выполнить ().Выгрузить ();
      запись = ? ( данные.Количество () = 0, неопределено, данные.Получить ( 0 ) );
      если ( запись = неопределено ) тогда
      	Стоп ( "Отсутствуют записи в регистре НДС с продаж по РН№ " + номер );
      конецесли;
      
      сумма = 52190;
      ндс = 9394.20;
      
      если ( запись.Сумма <> сумма
      	или запись.НДС <> ндс ) тогда
      	Стоп ( "Неверная запись в регистре НДС с продаж по РН№ " + номер );
      конецесли;

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

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

      Пример:

      п = новый Структура ();
      соединение.АвтоматическоеЗаполнениеОтчетности.ОписаниеПоказателей_РасчетПоНалогуНаПрибыль_2015Кв1 ( п );

      Как локализовать ошибку выполнения сценария при групповом запуске тестов?

      Иногда возникают ситуации, когда запуск сценария в ручном режиме происходит успешно, но при этом, групповой (ночной) запуск сценариев – выдает ошибку.

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

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

      попытка
      	Ввести ( "!МоеЧисловоеПоле", 10 );
      исключение
      	// Если что-то пошло не так,
      	// с этого места Тестер начнет отладку
      	// и будет ждать действий пользовтеля
      	ОтладкаСтарт ();
      конецпопытки;

      Почему отчет Сводка дает неверное (завышенное) время выполнения сценариев?

      Такая ситуация может возникать при вызове сценариев сценариями.

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

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

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

      Как проверять права доступа (или их отсутствие) к объектам?

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

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

      // Подключение к уже запущенному приложению
      // Для запуска приложения, см. общий тест Тестер.Запустить
      Подключить();
      
      объекты = "Номенклатура,Контрагенты";
      если ( ошибкаДоступа ( "Справочник", объекты, ложь ) ) тогда
      	Стоп ( "Возникли ошибки доступа. Детали см. в журнале ошибок" );
      конецесли;
      
      Функция ошибкаДоступа ( Тип, Список, ДоступДолженБыть )
      
      	ошибки = ложь;
      	для каждого объект из СтрРазделить ( Список, "," ) цикл
      		ЗакрытьВсе();
      		Коммандос ( "e1cib/list/" + Тип + "." + объект );
      		окноОшибки = Дождаться ( "1?:*" );
      		если ( окноОшибки ) тогда
      			форма = Здесь ( "1?:*" );
      			надпись = форма.НайтиОбъект ( , "Недостаточно прав *" );
      			если надпись = неопределено тогда
      				ЗаписатьОшибку ( "Какая-то ошибка при открытии объекта <" + объект + ">" );
      			иначе
      				если ( ДоступДолженБыть ) тогда
      					ЗаписатьОшибку ( "Недостаточно прав на объект <" + объект + ">" );
      					ошибки = истина;
      				конецесли;
      			конецесли;
      			Закрыть ( форма );
      		иначе
      			если ( не ДоступДолженБыть ) тогда
      				ЗаписатьОшибку ( "Прав доступа на объект <" + объект + "> быть не должно" );
      				ошибки = истина;
      			конецесли;
      		конецесли;
      	конеццикла;
      	возврат не ошибки;
      	
      КонецФункции

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

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

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

      Как узнать состояние флажка (галочки) на форме, перед тем как принять решение нажимать на него или не нажимать?

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

      флаг = Взять ( "!ЭтоУслуга" );
      если ( флаг = "Нет" ) тогда
      	Нажать ( "!ЭтоУслуга" );
      конецесли;
      // Здесь мы точно уверены, что флаг Услуга включен

      Как узнать, изменился ли заголовок тестируемой формы?

      Допустим, у вас стоит задача определить, что после определенных интерактивных действий с формой, ее заголовок остался неизменным. Для решения этой задачи можно использовать свойство ТекстЗаголовка тестируемой формы, например так:

      форма = Здесь ( "Мой заголовок формы *" );
      заголовок = форма.ТекстЗаголовка;
      // ... какие-то действия, которые могут привести к изменению заголовка
      новыйЗаголовок = форма.ТекстЗаголовка;
      если ( новыйЗаголовок <> заголовок ) тогда
      	Стоп ( "Изменился текст заголовка формы " + заголовок );
      конецесли;

      Как понять, что послужило зависанию или трудноуловимой ошибке в работе приложения (менеджера или клиента тестирования)?

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

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

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

      тут.Вставить ( "Адрес" );
      тут.Вставить ( "ID", новый UUID () );
      файл = "c:\данные.xlsx";
      ПоместитьФайл ( тут.Адрес, файл, файл, ложь, тут.ID );
      обработать ();
      данные = ПолучитьИзВременногоХранилища ( тут.Адрес );
      данные.Записать ( "c:\mydata.txt" );
      
      &НаСервере
      Процедура обработать ()
      
      	// Получаем переданные данные
      	данные = ПолучитьИзВременногоХранилища ( тут.Адрес );
      
      	//
      	// ...обрабатываем
      	//
      
      	// И возвращаем обратно
      	тут.Адрес = ПоместитьВоВременноеХранилище ( данные, тут.ID );
      
      КонецПроцедуры

      Как эмулировать двойной клик на строке таблицы?

      Для этого нужно получить объект тестируемой таблицы и выполнить метод Выбрать ():

      // Перейдем к нужной строке
      КСтроке ( "!Товары", "Наименование", "1С:Бухгалтерия 8" );
      // Выполним двойной клик
      Получить ( "!Товары").Выбрать ();

      Как отключить окно прогресса выполнения сценария?

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

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

      // Поместите эту строку в начало сценария
      ПрогрессСкрыть ();

      Как программно получить доступ к макету (табличному документу) сценария?

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

      Для решения этой задачи, можно воспользоваться следующим кодом:

      стек = Debug.Stack [ Debug.Level ];
      макет = RuntimeSrv.GetSpreadsheet ( стек.Module, стек.IsVersion ).Template;
      для а = 1 to макет.ВысотаТаблицы цикл
          для б = 1 to макет.ШиринаТаблицы цикл
              Сообщить ( макет.Область ( а, б ).Текст );
          конеццикла;
      конеццикла;

      Примечание: английские названия в примере непереводимы, это внутренняя реализация Тестера.

      Почему получение значения ячейки табличной части документа возвращает номер строки?

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

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

      Для решения проблемы, необходимо перед выполнением метода Взять (), активировать форму документа, это можно сделать методом Здесь ():

      ...
      документ = Здесь ( "Реализация товаров *" );
      товары = Получить ( "!Товары" );
      ...
      // Обязательно нужно указать второй параметр
      Здесь ( документ, истина );
      значение = Взять ( "!ТоварыЦена", товары );

      Как проверять движения документов и проводки, если проведение реализовано фоновым заданием?

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

      Например, в конфигурации ERP 2.4 используются фоновые задания для отмены проведения, проведения и формирования проводок по регламентированному учету.

      Пример ниже иллюстрирует проверку проводок по регламентированному учету для документа Приобретение услуг и прочих активов:

      Здесь ( "Приобретение услуг *" );
      Нажать ( "!ФормаПровести" );
      
      // Ожидаем окончание проведения 3 секунды
      Дождаться ( "Проведение", 3 );
      Нажать ( "!ФормаОбработкаОтражениеДокументовВРеглУчетеПроводкиРеглУчета" );
      
      // Запоминаем форму в переменную, чтобы потом вернуться к ней
      журнал = Здесь ();
      Нажать ( "!ФормаОтразитьДокументВРеглУчете" );
      
      // Перед тем как продолжать, ожидаем старт задания 3 секунды
      Дождаться ( "Старт задания", 3 );
      
      // Ждем, пока окно прогресса не закроется и мы не вернемся в журнал.
      // Максимальное ожидание 30 секунд.
      ждем = 30;
      пока ( ждем ) цикл
      	Дождаться ( "Формирование проводок", 1 );
      	если ( журнал = Здесь () ) тогда
      		прервать;
      	конецесли;
      	ждем = ждем - 1;
      конеццикла;
      
      // Здесь мы уже в журнале, где должны быть проводки.
      // Выводим проводки в табличный документ и проверяем результат.
      Нажать ("!ВывестиСписок");
      Нажать ( "!Ok", "Вывести список" );
      ПроверитьШаблон ( "", "Набор записей" );

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

      если ( ИмяКомпьютера () = "BusyServer" ) тогда
          __.Вставить ( "Производительность", 2 );
      иначе
          __.Вставить ( "Производительность", 1 );
      конецесли;

      Соответственно, в коде ожидания можно будет написать:

      Дождаться ( "Проведение", 3 * __.Производительность );

      Как работать с динамически сформированными полями, например в отчетах на СКД?

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

      Например, отчеты на базе СКД конфигурации ERP могут содержать такие идентификаторы полей:

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

      Фокус ( "!ЗначениеПараметраНастроек_Начало_520a2e1a7dd64881a5f5cf852bdd7a7f" );

      Для выхода из ситуации, можно использовать текст заголовка (даже если заголовок скрыт) с использованием символов-шаблонов поиска, например так:

      Фокус ( "*Начало*" );

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

      Как обойти таблицу или динамический список не зная сколько там записей?

      В некоторых сценариях, требуется обход коллекции с выполнением некоторого однотипного действия для для каждой её строки. Пример кода ниже, иллюстрирует подход к решению такой задачи: (пример на базе конфигурации БП3):

      Подключить ();
      ЗакрытьВсё ();
      Меню ( "Банк и касса / Платежные поручения" );
      Здесь ();
      список = Получить ( "!Список" );
      список.ПерейтиКПервойСтроке ();
      пока ( истина ) цикл
      	Сообщить ( Взять ( "!Дата", список ) );
      	попытка
      		список.ПерейтиКСледующейСтроке ();
      	исключение
      		прервать;
      	конецпопытки;
      конеццикла;
      Отключить ();

      Пример ниже для обхода табличной части Услуги документа Реализация:

      // Считаем, что документ уже открыт..
      Здесь ();
      таблица = Получить ( "!Услуги" );
      таблица.ПерейтиКПервойСтроке ();
      пока ( истина ) цикл
      	Сообщить ( Взять ( "!УслугиНомерСтроки", таблица ) );
      	попытка
      		таблица.ПерейтиКСледующейСтроке ();
      	исключение
      		прервать;
      	конецпопытки;
      конеццикла;

      Как программно получить последнюю ошибку упавшего сценария?

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

      Рассмотрим два варианта программного перехвата ошибки:

      // Первый случай
      Попытка
      	x = 1 / 0;
      Исключение
      	ошибка = ОписаниеОшибки (); // Здесь будет текст ошибки деления на 0
      КонецПопытки;
      
      // Второй случай
      Попытка
      	Вызвать ( "ПроверяемыйСценарий" ); // Допустим, в этом сценарии делается: x = 1 / 0;
      Исключение
      	ошибка = ОписаниеОшибки (); // Сюрприз, здесь не будет текста ошибки
      КонецПопытки;

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

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

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

      Попытка
      	Вызвать ( "ПроверяемыйСценарий" );
      Исключение
      	ошибка = последняяОшибка (); // Здесь будет ссылка, с представлением ошибки
      КонецПопытки;
      
      &НаСервере
      Функция последняяОшибка ()
      
      	с = "
      	|выбрать разрешенные первые 1 Журнал.Ref как Ссылка
      	|из Справочник.ErrorLog как Журнал
      	|где Журнал.User = &Пользователь
      	|упорядочить по Журнал.Date убыв
      	|";
      	з = новый Запрос ( с );
      	з.УстановитьПараметр ( "Пользователь", ПараметрыСеанса.User );
      	таблица = з.Выполнить ().Выгрузить ();
      	возврат ? ( таблица.Количество () = 0, неопределено, таблица [ 0 ].Ссылка );
      
      КонецФункции

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

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

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

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

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

      Стек = Debug.Stack [ Debug.Level ];
      Макет = RuntimeSrv.GetSpreadsheet ( стек.Module, стек.IsVersion ).Template;
      Эталон = Макет.Область ( 1, 1 ).Текст;

      Следующий шаг – экранирование эталонной строки:

      Эталон = экранировать ( Эталон );

      где функция:

      &НаСервере
      Функция экранировать ( Значение )
      
      	exp = Regexp.Get ();
      	exp.Pattern = "[.*+?^${}()|[\]\\]";
      	возврат exp.Replace ( Значение, "\$&" );
      	
      КонецФункции

      После экранирования, нужно заменить маркер на регулярное выражение:

      // Вместо "*" нам нужно примерно следующее, согласно лексике регулярных выражений: ".+"
      Эталон = Output.Sformat ( Эталон, новый Структура ( "Звезда", ".+" ) );

      На этом этапе, эталон готов к сравнению, и полный пример кода может выглядеть так:

      // Значение, которое нужно проверить
      Значение = "*** Здесь должно быть тестируемое значение ***";
      
      // Получение и обработка эталона
      Стек = Debug.Stack [ Debug.Level ];
      Макет = RuntimeSrv.GetSpreadsheet ( стек.Module, стек.IsVersion ).Template;
      Эталон = экранировать ( Макет.Область ( 1, 1 ).Текст );
      
      // Сравнение с использованием регулярных выражений
      если ( равны ( Эталон, Значение ) ) тогда
      	Сообщить ( "Равны" );
      иначе
      	Стоп ( "Не равны" );
      конецесли;
      
      &НаСервере
      Функция равны ( Эталон, Значение )
      
      	exp = Regexp.Get ();
      	// Будем требовать, чтобы строки были одинаковы с самого начала 
      	exp.Pattern = "^" + Эталон;
      	возврат exp.Test ( Значение );
      	
      КонецФункции
      
      &НаСервере
      Функция экранировать ( Значение )
      
      	exp = Regexp.Get ();
      	exp.Pattern = "[.*+?^${}()|[\]\\]";
      	стр = exp.Replace ( Значение, "\$&" );
      	возврат Output.Sformat ( стр, новый Структура ( "Звезда, Вопрос", ".+", "." ) );
      	
      КонецФункции

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

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

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

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

      Эта задача может быть решена созданием тест-метода получения идентификатора окружения.

      Создайте в библиотеке общих тестов такой метод:

      стэк = Debug.Stack [ Debug.Level - 1 ];
      если ( стэк.IsVersion
      	или не захвачен ( стэк.Module ) ) тогда
      	Пауза ( 1 );
      	значение = Цел ( ( ТекущаяУниверсальнаяДатаВМиллисекундах () / 1000 ) % 1000000000 );
      	возврат Conversion.DecToHex ( значение );
      иначе
      	возврат _;
      конецесли;
      
      &НаСервере
      Функция захвачен ( Модуль )
      
      	с = "
      	|выбрать разрешенные первые 1 1
      	|из Справочник.Scenarios как Сценарии
      	|	//
      	|	// Редактирование
      	|	//
      	|	соединение РегистрСведений.Editing as Редактирование
      	|	on Редактирование.Scenario = Сценарии.Ref
      	|	and Редактирование.User = &Я
      	|где Сценарии.Code = &Модуль
      	|";
      	з = новый Запрос ( с );
      	з.УстановитьПараметр ( "Модуль", Модуль );
      	з.УстановитьПараметр ( "Я", ПараметрыСеанса.User );
      	возврат не з.Выполнить ().Пустой ();
      
      КонецФункции

      И теперь, в ваших функциях создания окружения, вы можете использовать этот метод вот так:

      тест = окружение ( "2563E596" );
      создатьОкружение ( тест );
      
      // .....
      
      Функция окружение ( Идентификатор )
      
      	// Теперь, если вы не владеете этим тестом, ид-окружения
      	// будет каждый раз разным
      	ид = Вызвать ( "Общее.ИД", Идентификатор );
      	п = новый Структура ();
      	п.Вставить ( "ИД", ид );
      	п.Вставить ( "Поставщик", "_Поставщик " + ид );
      	п.Вставить ( "Организация", "Деловой союз" );
      	п.Вставить ( "Товары", определитьТовары ( ид ) );
      	возврат п;
      
      КонецФункции
      

      Как проверить, что отчет пустой?

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

      Например, чтобы проверить что такой отчет пустой:

      у менеджера тестирования нет возможности напрямую получить текст подсказки Отчет не сформирован...

      Однако, можно воспользоваться анализом размера области данных, применив такой подход:

      отчет = Получить ( "!Результат" );
      вширь = отчет.ПолучитьРазмерОбластиДанныхДокументаПоГоризонтали ();
      ввысь = отчет.ПолучитьРазмерОбластиДанныхДокументаПоВертикали ();
      если ( вширь + ввысь = 0 ) тогда
      	Стоп ( "Отчет не сформирован!" );
      конецесли;

      Почему скриншот формируется в виде черного квадрата?

      Это может происходить в одном из следующих случаев:

      1. Тестируемое приложение минимизировано
      2. Вы запускаете тестирование на удаленном сервере, к которому подключаетесь по RDP, и при этом:
        1. Приложение RDP-клиента свернуто (минимизировано)
        2. Вы не подключены к удаленной сессии

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

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

      [HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client]
      "RemoteDesktop_SuppressWhenMinimized"=dword:00000002

      С такой модификацией, свёрнутый RDP-клиент будет обновлять экран, и скриншоты уже не будут черными. Чтобы изменения вступили в силу, нужно перезапустить RDP-клиент.

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

      Таким образом, в своих скриптах CI, или тест-методах инициализации запуска, вы можете использовать примерно такой код:

      если ( ИмяКомпьютера () = "TestServer" ) тогда
      	ПерейтиВКонсоль ();
      конецесли;
      Следует учитывать, что консоль на сервере одна, поэтому если на вашем сервере запущено несколько сессий для тестирования, только одна в один момент времени может быть перенаправлена в серверную консоль

      Как проверить наличие навигационных ссылок у объекта?

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

      И если какой-то ссылки в панели нет, выдать сообщение об ошибке.

      Код ниже демонстрирует, как это можно реализовать:

      Здесь ( "О выдаче денеж*" );
      проверить = "Процессы и задачи, Переписка, Форум, Журнал передачи, Протокол работы";
      ссылкиНаФорме = взятьСсылки ();
      для каждого ссылка из Conversion.StringToArray ( проверить ) цикл
          если ( ссылкиНаФорме.Найти ( ссылка ) = неопределено ) тогда
              Стоп ( "Ссылка " + ссылка + " не найдена в навигационной панели" );
          конецесли;
      конеццикла;
      
      &НаКлиенте
      Функция взятьСсылки ()
      
          список = новый Массив ();
          для каждого ссылка из ПолучитьСсылки ().НайтиОбъекты () цикл
              список.Добавить ( ссылка.ТекстЗаголовка );
          конеццикла;
          возврат список;
      
      КонецФункции

      Как параметризировать шаблон сценария?

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

      Для решения этой задачи, можно использовать следующий подход:

      1. Сделать из шаблона макет
      2. Параметризировать нужные поля
      3. Написать небольшую функцию по заполнению параметризированного шаблона.

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

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

      // Готовим структуру для заполнения параметризированного шаблона
      п = новый Структура ( "Товар", "Комбайн MOULINEX  A77 4C" );
      
      // Так как я готовил и прогонял пример на основе демо-базы ERP,
      // то в качестве параметра я передаю конкретное название номенклатуры.
      // Однако, в случае проверки реальных тестовых данных, параметр можно
      // сформировать динамически, с учетом значения идентификатора, например:
      // п = новый Структура ( "Товар", "Номенклатура с упаковкой " + ид );
      
      // Вызываем функцию подготовки шаблона
      шаблон = подготовитьШаблон ( п );
      
      // Выполняем проверку, передавая ранее подготовленный шаблон
      // (подробнее о параметрах процедуры ПроверитьШаблон см. в справке)
      ПроверитьШаблон ( "", , , шаблон );
      
      &НаСервере
      Функция подготовитьШаблон ( Параметры )
      
      	стек = Debug.Stack [ Debug.Level ];
      	шаблон = RuntimeSrv.GetSpreadsheet ( стек.Module, стек.IsVersion );
      	макет = шаблон.Template;
      	область = макет.ПолучитьОбласть ();
      	область.Параметры.Заполнить ( Параметры );
      	макет.Очистить ();
      	макет.Вывести ( область );
      	возврат шаблон;
      	
      КонецФункции

      В результате, система проведет сравнение динамически подготовленного шаблона с табличным документом на стороне тестируемого приложения. В качестве примера, была взята табличная часть Товары документа Заказ клиента из конфигурации ERP:

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

      А можно в коде сценария объявить переменную области видимости весь сценарий?

      Объявить переменную в начале модуля, как это обычно делается в коде 1С, для сценария нельзя.

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

      Как подсчитать итог по колонке таблицы?

      Допустим, у вас есть такая таблица:

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

      таблица = Получить ( "!Товары" );
      таблица.ПерейтиКПервойСтроке ();
      сумма = 0;
      пока ( истина ) цикл
      	сумма = сумма + Взять ( "!ТоварыСумма", таблица );
      	попытка
      		таблица.ПерейтиКСледующейСтроке ();
      	исключение
      		прервать;
      	конецпопытки;
      конеццикла;
      ВСтудию ( сумма );

      Как проверить, что отчет после каких-либо действий не изменился?

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

      Код ниже демонстрирует подход к решению этой задачи на примере типовой конфигурации ERP2:

      Подключить ();
      ЗакрытьВсё ();
      
      // Откроем отчет и подождем пока он сформируется
      Коммандос ( "e1cib/app/Отчет.ABCXYZАнализНоменклатуры" );
      Нажать ( "!СформироватьОтчет" );
      Пауза ( 5 );
      
      // Запишем отчет в файл
      отчет = Получить ( "!ОтчетТабличныйДокумент" );
      файл = ПолучитьИмяВременногоФайла ( "mxl" );
      Приложение.УстановитьРезультатДиалогаВыбораФайла ( истина, файл );
      отчет.ЗаписатьСодержимоеВФайл ();
      
      // Далее, мы закрываем тестируемое приложение (см.метод Отключить),
      // делаем загрузку обновления конфигурации в пакетном режиме и другие действия.
      // Затем, мы заново запускам тестируемое приложение.
      //
      // ...здесь ваш код обновления и перезапуска тестируемого приложения...
      // ....................................................................
      
      // На этот момент приложение уже перезапущено, подключаемся,
      // открываем отчет ABC/XYZ - анализ номенклатуры и ждем формирования
      Подключить ();
      ЗакрытьВсё ();
      Коммандос ( "e1cib/app/Отчет.ABCXYZАнализНоменклатуры" );
      Нажать ( "!СформироватьОтчет" );
      Пауза ( 5 );
      
      // Далее, мы передадим на сервер ранее сохраненный файл отчета
      // и получим от него ТабличныйДокумент
      тут.Вставить ( "Адрес" );
      тут.Вставить ( "ID", новый UUID () );
      ПоместитьФайл ( тут.Адрес, файл, файл, ложь, тут.ID );
      УдалитьФайлы ( файл );
      
      // Получаем отчет-эталон в виде специальной структуры
      эталон = взятьШаблон ();
      
      // И теперь мы просто сверяем два отчета: текущий и ранее сохраненный
      ПроверитьШаблон ( "!ОтчетТабличныйДокумент", , , эталон );
      
      &НаСервере
      Функция взятьШаблон ()
      	
      	// Получаем переданные данные
      	данные = ПолучитьИзВременногоХранилища ( тут.Адрес );
      	файл = ПолучитьИмяВременногоФайла ( "mxl" );
      	данные.Записать ( файл );
      	макет = Новый ТабличныйДокумент ();
      	макет.Прочитать ( файл );
      	УдалитьФайлы ( файл );
      	
      	// Формируем проверяемые области, в нашем случае - это весь отчет
      	области = новый ТаблицаЗначений ();
      	колонки = области.Колонки;
      	колонки.Добавить ( "Up" );
      	колонки.Добавить ( "Bottom" );
      	колонки.Добавить ( "Left" );
      	колонки.Добавить ( "Right" );
      	область = области.Добавить ();
      	область.Up = 1;
      	область.Bottom = макет.ВысотаТаблицы;
      	область.Left = 1;
      	область.Right = макет.ШиринаТаблицы;
      	
      	// Возвращаем структуру данных, которую ожидает метод проверки шаблонов
      	возврат новый Структура ( "Template, Areas", макет, Collections.Serialize ( области ) );
      	
      КонецФункции

      Частые вопросы: Работа в среде

      Где синтаксическая подсветка кода?

      Можно установить Visual Studio Code, редактируемые там сценарии будут синхронизироваться с тестером в обе стороны. Подробнее см. в документации Интеграция с Visual Studio Code. При наборе кода сценария, кроме привычного IntelliSense работают подсказки к методам Тестера; разработанный плагин взаимодействует с Тестером для получения полей тестируемого приложения.

      Например, при наборе Нажать ( “ плагин покажет в выпадающем списке редактора vscode, какие кнопки можно нажать в текущем окне тестируемого приложения:

      Или, при установке текущий формы, подсказка будет такой:

      А как отлаживать сценарии?

      Для запуска сценария в режиме отладки, используется комбинация Alt+F5, либо контекстное меню в редакторе сценария Запустить отладку.

      Для установки точек останова, используется метод ОтладкаСтарт (). С его помощью можно остановить сценарий в нужном месте, либо сделать это по определенному условию:

      попытка
      	Ввести ( "!МоеЧисловоеПоле", 10 );
      исключение
      	// Если что-то пошло не так,
      	// с этого места Тестер начнет отладку
      	// и будет ждать действий пользовтеля
      	ОтладкаСтарт ();
      конецпопытки;

      Как по-быстрому прогнать пару сценариев?

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

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

      Находясь в сценарии:

      Каждый из пунктов предназначен для соответствующего анализа. Эти же функции доступны в контекстом меню дерева сценариев.

      Я редактирую тест и хочу его запустить на другой машине, я должен его предварительно помещать в хранилище?

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

      Как производить рефакторинг сценариев в процессе разработки?

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

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

      Например, вместо Ввести ( “Покупатель”, “Рога и копыта” ) используйте: Ввести ( “!Контрагент”, “Рога и копыта” ).

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

      Подход 2. Поиск используемого фрагмента в дереве сценариев, например так:

      Подход 3. Использование отчета Сценарии для точного поиска выражения:

      Подход 4. Рекомендуемый. Так как Тестер умеет автоматически зеркалировать сценарии на файловую систему, можно использовать богатые возможности внешних текстовых редакторов, например, Microsoft Visual Studio Code:

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

      Как вы работаете в vscode, там ведь кроме набора текста больше никаких удобств?

      Разработка сценариев в Visual Studio Code может стать очень удобным инструментом, хотя и требует определенной практики и изучение возможностей среды.

      Вот список наиболее полезных комбинации клавиш для работы с кодом сценария:

      Ctrl + E. Открывает окно нечеткого поиска сценария для его открытия в новой вкладке.

      Ctrl + Shift + E. Активация дерева файлов проекта.

      Alt + F12. Открытие в сплывающем окне модуля процедуры, функции или сценария. Удобно использовать для беглого просмотра когда связанного сценария.

      Ctrl + Shift + O. Быстрый переход к процедуре/функции кода сценария.

      Ctrl + Shift + F, Ctrl + Shift + H. Глобальный поиск и глобальная замена. Важной способностью этих функций является возможность указания начальной папки (поле чувствительно к регистру) поиска/замены.

      Частые вопросы: Автоматизация

      На тестовом сервере много баз и хранилищ, как указать Тестеру, какую базу прогонять и какие обновления в неё загружать?

      Используйте механизм версий и логику программного кода сценария. Такие методы как УстановитьПриложение () / УстановитьВерсию () / ПолучитьВерсию () могут быть использованы для организации условий запуска и обновления информационных баз. Полный пример будет подготовлен отдельной публикацией.

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

      Для этого нужно обратить внимание на два ключевых момента:

      1. Закрытие приложений при работе теста.
      2. Закрытие приложений перед началом тестирования.

      Закрытие приложений при работе теста

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

      // Отключаемся от текущей тестируемой сессии
      Отключить ();
      
      // Где-то в структуре данных у вас должен быть порт для
      // запуска новой тестируемой сессии
      порт = Окружение.ПортУтверждающегоЗаявки;
      
      // Перед запуском новой сессии, попробуем вначале к ней подключиться
      попытка
      	Подключить ( , порт );
      	завершить = истина;
      исключение
      	завершить = ложь;
      конецпопытки;
      если ( завершить ) тогда
      	// Здесь мы уже подключены к старой сессии.
      	// Закроем в ней все окна и отключаемся с завершением работы приложения
      	ЗакрытьВсё ();
      	Отключить ( истина );
      конецесли;
      
      // Здесь мы уверены, что предыдущая сессия на этом порту завершена
      // и запуск новой сессии будет занимать ожидаемый порт
      // и ожидаемо контролироваться сценарием
      п = Вызвать ( "Тестер.Запустить.Параметры");
      п.Пользователь = "Петров";
      п.База = "Бухгалтерия предприятия";
      п.Порт = порт;
      Вызвать ( "Тестер.Запустить", п );

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

      Закрытие приложений перед началом тестирования

      Закрывайте тестируемые приложения перед запуском тестов и до обновления конфигурации.

      Так нужно делать по нескольким причинам:

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

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

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

      с = СвойстваПриложения.Port;
      до = 5;
      для порт = с по c + до цикл
      	попытка
      		Подключить ( , порт );
      		Отключить ( истина );
      	исключение
      	конецпопытки;
      конеццикла;

      Алгоритм выше, опирается на факт возможного наличия тестовых клиентов в диапазоне от порта приложения (задается в справочнике Приложения) до 5 одновременных сессий. Отсюда, следует рекомендация: при запуске дополнительных сессий, используйте не фиксированные порты, а относительные, с инкрементацией к значению порта, заданного в свойствах приложения.

      Как исключить тесты разрабатываемого функционала от ночного прогона?

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

      Вариант 1. Создать отдельную группу тестов, и исключить её из выборки сценариев для тестирования (см. тест Сценарии в репозитории общих тестов).

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

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

      Как запустить тестирование из командной строки?

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

      Подробнее о параметрах запуска с примерами, см. ПараметрыЗапуска.

      Какой самый простой способ группового запуска сценариев по расписанию?

      Организация полноценного CI/CD реализуется в Тестере специальным набором общих тест-методов, но что если вам нужно максимально быстро организовать запуск тестов по расписанию, где-то на виртуальной машине? Для этого, можно создать тест-метод, который будет внутри себя содержать некий список сценариев, и выполнять их один за другим.

      Вот пример такого теста:

      тесты = новый Массив();
      тесты.Добавить("полный.путь.к.тесту1");
      тесты.Добавить("полный.путь.к.тесту2");
      тесты.Добавить("полный.путь.к.тесту3");
      запустить(тесты);
      
      Процедура запустить(Тесты)
      
          для каждого тест из Тесты цикл
              попытка
                  Test.Start(тест);
              исключение
                  попытка
                      ЗакрытьВсе();
                  исключение
                  конецпопытки;
              конецпопытки;
          конеццикла;
      
      КонецПроцедуры

      Созданный тест с начинкой выше, затем можно запускать по расписанию, подробнее см.Механизм заданий.

      Частые вопросы: Концептуальные

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

      Зачем программисту автоматизированное тестирование?

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

      Почему в Тестере, все сценарии в виде программного кода?

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

      А можно не кодировать вручную, а записывать сценарий?

      Да. В Тестере реализовано несколько механизмов формирования сценария:

      Вариант 1: Пишется код вручную.

      Плюсы:

      Минусы:

      Вариант 2: Сценарий пишется по действиям пользователя (см. на панели микрофон).

      Плюсы:

      Минусы:

      Вариант 3: Использование мастера (см. на панели подбор действия).

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

      Плюсы:

      Минусы:

      Общая рекомендация: если вы программист, пишите сценарии кодом.

      Почему в Тестере нет средств загрузки начальных данных из макета или файла?

      Одной из фундаментальных задач при разработке Тестера было желание создать систему, при которой промежуток времени, между написанием кода и его тестом, был бы минимальным. Данная цель была достигнута; следствием стало накопление большого числа тестов: сотни, а для некоторых проектов, тысячи. Такая ситуация предъявляет особые требования к содержанию, прогону и анализу результатов тестирования, с которой мы в свое время успешно не справились.

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

      Программный код воплотил собой отсутствие в тестере каких-либо механизмов выгрузки/загрузки данных. Подробнее о реализации подхода читайте в документации Данные для тестирования.

      Как организовать специальный порядок выполнения тестов?

      Желательно этого не делать; правильным решением является несвязность и независимость сценариев от очередности запуска.

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

      Такой подход неизбежно приведет к следующим проблемам:

      1. Падение одного теста, послужит источником ложного падения от него зависимых. Это может обернуться катастрофой, потому что при растущем количестве тестов, будет очень сложно вычислять точки падения, и разбирать цепочки, отматывая назад зависимости с целью определения реальных ошибок.
      2. Сложность рефакторинга связанных тестов, по причине исполнения ими двух ролей: проверка себя и поставка окружения другим сценариям. Естественное нежелание модифицировать работающие зависимости, заканчивается слабым покрытием растущего функционала решения.
      3. Сложность распараллеливания тестов. Когда тестов будет много, либо в их логике будет производиться долгая обработка данных, ночи на прогон может не хватить. Потребуется распараллеливание. Эту задачу будет очень сложно решить для связанных тестов.

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

      История релизов

      1.3.4.4

      1. Исправлена ошибка запуска сценариев не из под агентов

      1.3.4.3

      1. Устранена плавающая проблема задержки запуска теста на выполнение из vscode
      2. В отчеты Протокол и Сводка добавлена возможность анализа выполнения выполняющегося задания

      1.3.4.2

      1. Доработана стандартная проверка ошибки проведения документов для версии платформы 8.3.15
      2. Исправлена ошибка зависания выгрузки теста для редактирования в vscode, в случае, если папки тестов находятся на разных дисках компьютера
      3. Поправлена справочная система, вызываемая внутри тестера (в рамках предоставляемых платформой возможностей)

      1.3.4.1

      1. Доработано поведение метода Фокус(Activate) при работе с таблицами. Теперь, метод вначале находит указываемую строку, затем, активирует колонку
      2. Добавлено логирование полного текста ошибки. Ранее, строка с ошибкой содержала максимум 150 символов.
      3. Добавлена возможность копирования сценариев включая иерархию. Копирование возможно как по отдельной команде в контекстном меню дерева сценариев, так и путем Drag & Drop в дереве, с прижатой кнопкой Ctrl.
      4. Перенос и копирование сценариев теперь также производят выгрузку в файлы в случае смонтированных приложений.
      5. Решена проблема создания под-сценария, в случае когда сценарий-родитель открыт в режиме на редактирование. Теперь при создании под-сценария, сценарий родитель будет записан, и затем – перечитан.
      6. Изменена логика перехода к ошибкам в случае падения сценариев. Теперь двойной клик по сообщению с ошибкой или открытие ошибки из отчета, приводит к показу окна с подробностями об ошибке, с дальнейшей возможность перейти по стеку или в журнал ошибок.

      1.3.3.9

      Внимание! После обновления конфигурации на версию 1.3.3.9 следует запустить Тестер в режиме 1С:Предприятие и выполнить обработку ПереходНа1.3.3.9.epf
      1. Реализована команда запуска сценария в режиме записи в хронограф
      2. Переработана логика хранения тестовых сессий: отчет Сводка теперь формируется за период, а не с даты начала запуска тестов.
      3. Исправлены обнаруженные ошибки совместимости работы конфигурации с различными версиями платформы

      1.3.3.8

      1. Реализован хронограф
      2. Реализована переменная тут области видимости весь сценарий
      3. В API добавлены методы по отображению/скрытию окна прогресса выполнения сценария

      1.3.3.7

      1. В API тестера добавлена работа с текучими выражениями.

      1.3.3.6

      1. В метод Нажать добавлена возможность нажимать на сворачиваемые группы. При этом, группа будет развернута/свернута в зависимости от состояния на момент вызова.

      1.3.3.5

      1. Добавлена возможность запуска на выполнение выделенного фрагмента кода в редакторе vscode (по комбинации ctrl+alt+R). Требуется обновление плагина vscode до версии 0.0.10.

      1.3.3.4

      1. Добавлен метод ПерейтиВКонсоль для решения проблемы формирования скриншотов в виде черного квадрата

      1.3.3.2

      1. Доработан случай нажатия на гиперссылку без заголовка

      1.3.3.1

      1. Реализована возможность подключения тестера к тестируемым клиентам разных версий платформы (особенности и ограничения см. в документации к методу Подключить)
      2. Метод Коммандос стал функцией и теперь автоматически выполняет метод Здесь для открываемых им форм (подробности в документации)
      3. Метод Нажать теперь умеет нажимать гиперссылки в декорациях (начиная с версии 8.3.13, подробности в документации)
      4. Запуск выделенной части сценария теперь учитывает смещение в модуле, в случае возникновения ошибки в выделенном фрагменте
      5. Метод Отключить вторым параметром может принимать булево значение ПотушитьПрокси (по умолчанию – ложь), для отключения проксирования соединений с клиентами тестирования (подробности в документации)
      6. Метод Пауза теперь использует API операционной системы, и больше не загружает процессор
      7. Улучшено сворачивание заголовков отчетов: учтена особенность работы СКД в зависимости от версии платформы и режимов совместимости
      8. Компоновщик кода теперь не выдает ошибок в случае замыкающего комментария после ключевого слова КонецПроцедуры (КонецФункции)
      9. Реализована возможность подбора полей в случае отсутствия подключения к клиенту тестирования
      10. В помощнике подбора полей, реализована возможность пере-подключения к приложениям со сменой порта
      11. Исключена ситуация одновременного запуска одного задания на тестирование (без назначенного компьютера) сразу несколькими свободными агентами тестирования
      12. Добавлен параметр важности сценария, учтен в журналах и отчетах
      13. Добавлен регистр сведений Исходники для хранения информации о выгрузках конфигурации
      14. Внешняя компонента дополнительных функций Тестера теперь не опциональна, и подключается всегда
      15. При попытке проверить пустой шаблон будет вызвано исключение
      16. Исправлена ошибка проверки по шаблону *xxx
      17. Обновлен плагин взаимодействия vscode с Тестером

      API Тестера

      Программный код сценария выполняется на клиенте в режиме Тонкий клиент. В тексте сценариев допускается создание клиент-серверных процедур и функций. Для взаимодействия с тестируемым приложением, Тестер предлагает в использование небольшое число оберток над объектами тестируемого приложения платформы 1С:Предприятие. Обертки создавались по принципу частотности практического применения и организованы в виде глобальных функций с короткими именами для простоты написания кода.

      Работа с тестируемым приложением может быть выполнена на чистом API платформы, за дополнительной информацией обращайтесь на сайт ИТС, а также см. в конфигураторе синтаксис-помощник по объекту ТестируемоеПриложение.

      Внимание! Выполнение серверного кода сценария выполняется в небезопасном режиме.
      Серверный код сценариев выполняется в контексте конфигурации Тестера, а не тестируемого приложения.

      Переменные

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

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

      Name Description

      Приложение

      App

      Тестируемое приложение, объект 1С ТестируемоеПриложение. Может использоваться кодом сценария для вызова методов платформы.

      окно = Приложение.ПолучитьАктивноеОкно ();
      окно.Закрыть ();

      При запуске теста, данная переменная не определена.

      Переменная устанавливается при выполнении метода Подключить ().

      ИмяПриложения

      AppName

      ИД приложения запускаемого теста. Может использоваться кодом сценария для идентификации тестируемой конфигурации.

      если ( ИмяПриложения = "ERP20" ) тогда
          Сообщить ( "Тестируется ERP" );
      конецесли;

       

      СвойстваПриложения

      AppData

      Структура свойств тестируемого приложения. Инициализируется перед запуском и доступна в коде сценария.

      Содержит следующие поля:

      Поле Значение
      Scenario Ссылка на запускаемый сценарий
      Application Ссылка на приложение
      Computer Имя компьютера, где производится подключение к тестируемому приложению
      Port Порт клиента тестирования с учетом порта, который может быть уточнен для конкретной сессии (см. Приложения)
      ClientID Идентификатор веб-клиента, при тестировании веб-клиента
      Connected Булевый признак подключения к тестируемому приложению
      Proxy Порт прокси, если задан
      Localhost Строка с IP-адресом локального сетевого адаптера в случае проксирования соединения
      Version Строка с версией платформы, если соединение проксируется и версия задана
      ConnectedHost

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

      Эти значения могут отличаться от полей Computer и Port, в том случае, когда адрес и порт были переданы непосредственно в метод Подключить выполняемого сценария.

      ConnectedPort

       

      ЗаголовокДиалогов

      DialogsTitle

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

      вопрос = Приложение.НайтиОбъект ( Тип ( "ТестируемаяФорма" ), ЗаголовокДиалогов );
      если ( вопрос <> неопределено ) тогда
      	Нажать ( "Да", вопрос );
      конецесли;

       

      ГлавноеОкно

      MainWindow

      Главное окно приложения, тип ТестируемоеОкноКлиентскогоПриложения.

      Может использоваться кодом сценария для вызова методов платформы.

      ГлавноеОкно.ПерейтиКНачальнойСтранице ();

      При запуске теста, данная переменная не определена.

      Заполняется при выполнении метода Подключить ().

      ТекущийОбъект

      CurrentSource

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

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

      Источником может выступать любой визуальный объект тестируемого приложения, имеющий внутри себя подчиненные визуальный элементы. Примеры: Форма, Группы формы, Таблица.

      Устанавливать вручную данную переменную не рекомендуется. Используйте метод Здесь (With) для таких целей.

      __ (double underscore) Глобальная пользовательская переменная, которая доступна всем сценариям. Каждый разработчик сценария может использовать данную переменную по своему усмотрению.

      тут

      this

      Локальная структура области видимости сценария, передается на сервер.

      Пример:

      тут.Вставить ( "Товар", "Клавиатура Logitech" );
      вывести ();
      взятьСсылку ();
      ВСтудию ( тут.Ссылка );
      
      &НаКлиенте
      Процедура вывестиТовар ()
      
          ВСтудию ( тут.Товар );
      
      КонецПроцедуры
      
      &НаСервере
      Процедура взятьСсылку ()
      
          ссылка = Справочники.Товары.НайтиПоНаименованию ( тут.Товар );
          тут.Вставить ( "Ссылка", ссылка );
       
      КонецПроцедуры

       

      Debug.Delay

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

      Debug.Error

      Булевый флаг, являющийся признаком произошедшей ошибки в выполняемом сценарии.

      Сам текст ошибки хранится в журнале ошибок, которым является справочник Журнал ошибок (Log). Используя серверные функции, можно получать ошибки выполнения тестов.

      Debug.Job

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

      Структура содержит следующие поля:

      Поле Значение
      Job Ссылка на выполняемое задание
      Row Номер строки выполняемого сценария документа Задание.

      Пример получения параметров выполняемого задания:

      задание = Debug.Job.Job;
      параметры = Conversion.FromJSON ( DF.Pick ( задание, "Parameters" ) );
      Сообщить ( параметры.Параметр1 );

       

      Мета

      Meta

      Метаданные приложения, пример использования:

      Сообщить ( Мета.Справочники.ВидыНоменклатуры.Synonym );

      Метаданные могут быть использованы для унификации получения представления объектов метаданных.

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

      Меню ( "НСИ и администрирование / Номенклатура" );

      В этом случае, платформа откроет форму списка справочника. Для того, чтобы дальше взаимодействовать с данной формой, её необходимо установить текущей. Для этого используется метод Здесь (With). Этому методу, в качестве параметра, нужно передать строку. Чтобы сделать форму текущей, необходимо передать заголовок формы.

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

      Меню ( "НСИ и администрирование / Номенклатура" );
      
      // Первый способ: просто передаем заголовок формы
      Здесь ( "Номенклатура" );
      
      // Второй способ: используем метаданные
      Здесь ( Мета.Справочники.Номенклатура.Synonym );

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

      Так как Тестер не может напрямую общаться с тестируемым приложением на программном уровне, метаданные для Тестера нужно готовить. Для подготовки метаданных используется обработка Meta.epf. Эту обработку можно скачать из формы справочника Приложения.

      СтандартнаяОбработка

      StandardProcessing

      Переменная, определяющая стандартное поведение сценария. Переменная задается на уровне каждого сценария и автоматически устанавливается в значение Истина перед каждым запуском сценария.

      Если СтандартнаяОбработка = Истина тогда Тестер, после окончания выполнения каждого сценария, выполняет следующие действия:

      1. Проверяет наличие сообщений пользователю. Если сообщения есть – считается, что возникла ошибка. Тестер выкидывает исключение.
      2. Восстанавливается ТекущийОбъект, который был задан до вызова текущего сценария.

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

      Пример 1.

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

      Пример 2.

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

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

      ИгнорироватьОшибки

      IgnoreErrors

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

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

      Нажать ( "Провести" );
      // Здесь тестер неявно проверит на ошибки

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

      В этом случае, необходимо флаг ИгнорироватьОшибки установить в Истина, провести документ, проверить наличие сообщений об ошибке и вернуть ИгнорироватьОшибки обратно в значение Ложь:

      // Отключаем проверку ошибок
      ИгнорироватьОшибки = истина;
      
      // Проводим документ с заведомо ошибочной ситуацией
      Нажать ( "Провести" );
      
      // Ищем сообщения: 1) Диалоговое окно 2) Непосредственно сообщения
      если ( НайтиСообщения ( "Не удалось провести*" ).Количество () = 0 ) тогда
      	Стоп ( "<Не удалось провести*> диалоговое окно должно быть показано" );
      конецесли;
      
      Нажать ( "OK", Forms.Get1C () ); // Закрыть стандартное 1С окно
      
      если ( НайтиСообщения ( "Недостаточно товара * на складе *" ).Количество () <> 1 ) тогда
      	Стоп ( "<" + _ + "> сообщение об ошибке должно быть показано один раз" );
      конецесли;
      
      // Возвращаем проверку ошибок
      ИгнорироватьОшибки = ложь;
      Подробнее об особенности метода Коммандос в случае включения флага ИгнорироватьОшибки = истина, читайте здесь.

      СпециальныеПоля

      SpecialFields

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

      Данная структура также используется в некоторых внутренних функциях Тестера для автоматической навигации. Например, при активации табличной части, Тестер анализирует, есть ли в таблице активная строка и если нет, пытается активировать первую строку таблицы. Для такой активации, тестер использует структуру СпециальныеПоля для определения названия колонки с номером. В русской конфигурации это будет N, в английской #.

      ПараметрыЗапуска

      LaunchParameters

      Глобальное соответствие, содержащие параметры запуска Тестера.

      Параметры запуска передаются по ключу /C при запуске 1С:Предприятие 8.3.

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

      "C:\Program Files (x86)\1cv8\8.3.10.2252\bin\1CV8C.exe" /IBName"Infobase" /N"Администратор" /TESTMANAGER /C"-ParameterName1 ParameterValue1 -ParameterName2 ParameterValue2"

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

      // Выведет ParameterValue1
      Сообщить ( ПараметрыЗапуска [ "ParameterName1" ] );

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

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

      Scenario Полный путь к запускаемому сценарию. Если данный ключ задан – Тестер запустит указанный сценарий на выполнение
      Application Название приложения. Указанное приложение будет установлено в качестве тестируемого при запуске тестовой сессии

      Пример ниже выполняет запуск некоторого сценария из командной строки:

      "C:\Program Files (x86)\1cv8\8.3.10.2252\bin\1CV8C.exe" /IBName"Infobase" /N"Администратор" /TESTMANAGER /C"-Scenario МойСценарий -Application МоеПриложение -SomeParameter1 SomeValue1"

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

      "C:\Program Files (x86)\1cv8\8.3.10.2252\bin\1CV8C.exe" /IBName"Infobase" /N"Администратор" /TESTMANAGER /C"МоеПриложение#МойСценарий"
      В обоих примерах запуска сценария на выполнение, указание приложения не обязательно
      ScreenshotsLocator

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

      Необходимость в изменении данной переменной может возникнуть по ходу теста в случае, если в таком тесте идет тестирование сразу нескольких приложений (см. здесь).

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

      ВыполняетсяДелегированноеЗадание

      RunningDelegatedJob

      Глобальная переменная булевого типа. Принимает значение Истина когда агент начинает выполнение делегированного ему задания. Если текущий пользователь не агент, значение переменной принимает значение Неопределено.

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

      Подробнее об агентах и заданиях см. в разделе Механизм заданий.

      ЯАгент

      IAmAgent

      Глобальная переменная булевого типа. Принимает значение Истина для пользователей-агентов. Значение переменной присваивается при старте системы и за время жизни сеанса не изменяется.

      Подробнее об агентах и заданиях см. в разделе Механизм заданий.

      Методы

      Наименование Возвращаемое значение Описание

      Подключить ( ОчищатьОшибки = истина, Порт = неопределено, Компьютер = неопределено )

      Connect ( ClearErrors = true, Port = undefined, Computer = undefined )

       

       

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

      Внимание! Взаимодействие менеджера и клиента тестирования через проксирование является нештатной возможностью, и может приводить к непредсказуемым результатам. Используйте прокси в тех крайних случаях, когда версии платформ менеджера и клиента сопоставить нельзя. Также, следует учитывать следующие ограничения и особенности:
      1. Проксирование работает локально
      2. Проксирование нестабильно при взаимодействии с разными мажорными версиями платформ (например, взаимодействие между клиентом 8.3.13 и менеджером 8.3.14 может приводить к падению клиента)
      3. Проксирование не работает для Web-клиента

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

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

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

      Test.ConnectClient ( false );

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

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

      Компьютер: Строка. Передается IP-адрес или сетевое имя компьютера, на котором запущено тестируемое приложению. Если не задан тогда будет использован порт из справочника Приложения.

      Отключить ( Закрыть = ложь, ТушитьПрокси = ложь )

      Disconnect ( Close = false, ShutdownProxy = false )

       

      Производит отключение от тестируемого приложения.

      Закрыть: Если Истина тогда тестируемое приложение будет закрыто.

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

      ЗакрытьВсе(ё) ()

      CloseAll ()

       

      Закрывает все окна в тестируемом приложении. Если есть окна с несохраненными данными, Тестер будет пытаться ответить Нет на возникающие вопросы системы.

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

      Закрыть ( Форма = неопределено )

      Close ( Form = undefined )

       

      Закрывает форму.

      Форма: может быть передан заголовок окна или непосредственно форма, которую требуется закрыть.

      Если параметр Форма не задан, тогда будет закрыт ТекущийОбъект.

      Данный метод не анализирует признак модифицированности формы и не пытается ответить на вопрос о сохранении данных.

      Здесь ( Имя = неопределено, Активировать = ложь )

      With ( Name = undefined, Activate = false )

      Тестируемый объект

      Определяет значение глобальной переменной ТекущийОбъект согласно найденного визуального объекта.

      Имя: Если в параметр передать строку, тогда метод будет искать объекты следующих типов:

      1. ТестируемоеОкноКлиентскогоПриложения (TestedClientApplicationWindow)
      2. ТестируемаяФорма (TestedForm)

      В строке могут использоваться символы * и ? для поиска по шаблону.

      Если в метод передается объект, метод установит ТекущийОбъект равный переданному объекту.

      Если параметр опущен, текущим источником будет установлена текущая активная форма.

      Активировать: булево значение, если истина – найденный объект будет активирован. Параметр может использоваться для переключения между открытыми неблокирующими формами.

      Примеры:

      Здесь ( "Номенклатура" ); // Тестер будет искать форму с заголовком "Номенклатура"
      форма = Здесь ( "Заказ покупателя (соз*" ); // Метод также может возвращать значения. Также, могут использоваться автоподстановочные знаки
      Здесь (); // Текущая форма

       

      Получить ( Имя, Источник = неопределено, Тип = неопределено )

      Get ( Name, Source = undefined, Type = undefined )

      Тестируемый объект

      Возвращает тестируемый объект.

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Кнопка, КоманднаяПанель, КомандныйИнтерфейс, КонтекстноеМеню, Декорация, Поле, Форма, Группа, КнопкаКИ, ГруппаКИ, Таблица, Окно.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Примеры:

      поле = Получить ( "Сумма" ); // Получить поле Сумма. Надпись к полю будет использована при поиске объекта
      
      поле = Получить ( "!Сумма" ); // Тоже самое, но при поиске будет использован идентификатор поля. Такой вариант получения полей может быть использован для многоязычных конфигураций
      
      поле = Получить ( "Товары / Итого" ); // Вначале будет найден объект Товары, а затем внутри него будет найдено поле Итого. Префиксы "!", "#" могут быть использованы в любой части выражения
      
      поле = Получить ( "!ТабличныйДокумент [R1C1]" ); // Вернет ячейку поля табличного документа
      
      таблица = Фокус ( "!Товары" );
      поле = Получить ( "!ТаблицаКоличество [ 2 ]", таблица ); // Вернет поле Количество во второй строке таблицы Товары

       

      Взять ( Имя, Источник = неопределено, Type = неопределено )

      Fetch ( Name, Source = undefined, Type = undefined )

      Строка

      Возвращает строковое представление значения объекта.

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Поле.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Примеры:

      код = Взять ( "Дополнительно / Код" );
      
      текст = Взять ( "!ТабличныйДокумент [R1C1]" ); // Вернет значение в этой ячейке
      
      таблица = Фокус ( "!Товары" );
      поле = Взять ( "!ТоварыКоличество [ 2 ]", таблица ); // Вернет значение количества во второй строке таблицы Товары. Внимание! Возвращаемое значение будет отформатировано согласно региональных настроек информационной базы и сеанса

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

      Установить ( Имя, Значение, Источник = неопределено, Тип = неопределено )

      Set ( Name, Value, Source = undefined, Type = undefined )

      Тестируемый объект

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

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Поле.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

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

      Примеры:

      // Устанавливает значение в поле
      Установить ( "#Комментарий", "Важный комментарий" );
      
      // Устанавливает количество в новой строке таблицы
      Нажать ( "!ТоварыДобавить" );
      Установить ( "!ТоварыКоличество", 7 );
      
      // Устанавливает количество во второй строке, пример 1
      таблица = Фокус ( "!Товары" );
      Установить ( "!ТоварыКоличество [ 2 ]", 15, таблица );
      
      // Устанавливает количество во второй строке, пример 2
      Установить ( "!ТоварыКоличество [ 2 ]", 15, Получить ( "!Товары" ) );
      
      // Устанавливает значение в ячейке табличного документа
      Установить ( "!ПечатныйДокумент [R1C1]", "Привет мир" );

       

      Ввести ( Имя, Значение, Источник = неопределено, Тип = неопределено, ПроверитьЗначение = ложь )

      Put ( Name, Value, Source = undefined, Type = undefined, TestValue = false )

      Тестируемый объект

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

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

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

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

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

      Очистить ( Имя, Источник = неопределено, Тип = неопределено )

      Clear ( Name, Source = undefined, Type = undefined )

      Тестируемый объект

      Очищает поле.

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Поле

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Подобрать ( Имя, Значение, Источник = неопределено, Тип = неопределено )

      Pick ( Name, Value, Source = undefined, Type = undefined )

       

      Производит выбор значения из списка выбора.

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Поле.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Примеры:

      таблица = Фокус ( "!Товары" );
      Подобрать ( "!ТоварыТип [ 2 ]", "Услуга", таблица );

       

      Фокус ( Имя, Источник = неопределено, Тип = неопределено )

      Activate ( Name, Source = undefined, Type = undefined )

      Тестируемый объект

      Активирует поле.

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Кнопка, КоманднаяПанель, Декорация, Поле, Форма, Группа, Таблица, Окно.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Примеры:

      Фокус ( "!ТабДок [R1C1]" );
      
      таблица = Фокус ( "!Товары" );
      Фокус ( "!ТоварыКоличество [ 2 ]", таблица );

      Нажать ( Имя, Источник = неопределено, Тип )

      Click ( Name, Source = undefined, Type = undefined )

      Тестируемый объект

      Активирует и нажимает на поле. Также, может использоваться для нажатия на гиперссылку в декорации (начиная с версии платформы 8.3.13) и сворачиваемую группу.

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Кнопка, Декорация, ПолеКнопкаКИ.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Примеры:

      // Нажать чекбокс если Товар не Услуга
      нажать = ? ( услуга, "Да", "Нет" ) <> Взять ( "!ЭтоУслуга" );
      если ( нажать ) тогда
      	Нажать ( "!ЭтоУслуга" );
      конецесли;
      
      // Нажать в табличной части
      таблица = Фокус ( "!Товары" );
      Нажать ( "!ТоварыРезервировать [ 2 ]", таблица );
      
      // Нажать на гиперссылку в декорации
      Нажать ( "!ДокументОснование" );
      
      // Нажать на вторую гиперссылку в декорации
      Нажать ( "!Ссылки[2]" );
      
      // Нажать на определенную гиперссылку в декорации.
      // Обратите внимание:
      // 1. Для нажатия на ссылку по заголовку, нужно использовать точное представление, подстановочные символы не допускаются
      // 2. Для того, чтобы правильно была переда надпись, слэши экранируются обратными слешами
      Нажать ( "!Ссылки[Поступление ТМЦ №123456 от 01\/\/01\/2019]" );

       

      Вызвать ( Сценарий, Параметры = неопределено, Приложение = неопределено )

      Call ( Scenario, Params = undefined, Application = undefined )

      Любое значение

      Выполняет запуск сценария по переданным пути и параметрам.

      Сценарий: Полный путь к запускаемому сценарию (каждый сценарий в системе имеет уникальный путь в пределах приложения).

      Параметры: любое значение, которое будет передано в вызываемый сценарий. Вызванный сценарий может обращаться к переданным параметрам через переменную “_”. В качестве параметра допускается передача строки в формате JSon. В этом случае, строка будет преобразована в структуру и вызываемый сценарий получит в переменную “_” структуру параметров.

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

      Пример:

      // Пример 1
      Вызвать ( "Общее.ОткрытьСписок", Мета.Справочники.Номенклатура );
      
      // Пример 2
      п = новый Структура ();
      п.Вставить ( "Товар", "Втулка" );
      п.Вставить ( "Цена", "150" );
      Вызвать ( "МойТест", п );
      
      // В теле МойТест обращение к переданным параметрам идет через _
      Сообщить ( _.Товар ); // Втулка
      
      // Пример 3. Тоже самое как и в Пример 2, только через строку JSon
      Вызвать ( "МойТест", "{'Товар': 'Втулка', 'Цена': '150'}" );
      
      // В теле МойТест обращение к переданным параметрам идет через _
      Сообщить ( _.Товар ); // Втулка
      

       

      Позвать ( Сценарий, Параметры = неопределено, Приложение = неопределено )

      Run ( Scenario, Params = undefined, Application = undefined )

      Любое значение

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

      Пример:

      Вызвать ( "Справочник.Номенклатура.Создать.Параметры" ); // Полный путь
      Позвать ( "Создать.Параметры" ); // Будет работать, если вызывающий тест находится внутри "Справочник.Номенклатура"

       

      Test.Start ( Scenario, Application = undefined )

      * Метод не имеет русскоязычного аналога, потому что является частью программной реализации Тестера
      Булево

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

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

      Scenario: Полный путь к запускаемому сценарию (каждый сценарий в системе имеет уникальный путь в пределах приложения).

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

      Пример:

      если ( Test.Start ( "Инвойс.Создать" ) ) тогда
         Test.Start ( "Инвойс.Провести" );
      конецесли;

       

      Меню ( Путь )

      OpenMenu ( Path )

       

      Открывает ссылку на объект в глобальном командном интерфейсе.

      Путь: строка к объекту, разделенная символом “/”. 

      Работа данного метода имеет следующую особенность: если в открываемом объекте, содержится программная ошибка, возникающая до открытия основной формы объекта, такая ошибка не может быть перехвачена Тестером и программно обработана кодом сценария (например, через попытку/исключение). Таким образом, если вы используете в коде сценария, собственный механизм перехвата сообщений об ошибках, для открытия объектов нужно использовать Коммандос (), вместо Меню ()

      Пример:

      Меню ( "Продажи / Заказы клиентов" ); // Откроет подсистему Продажи и "нажмет" на Заказы клиентов

       

      Выбрать ( Имя, Источник = неопределено, Тип = неопределено )

      Choose ( Name, Source = undefined, Type = undefined )

      Тестируемый объект

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

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Поле.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Примеры:

      // Равносильно нажатию на кнопку выбора в поле Покупатель
      Выбрать ( "Покупатель" );
      
      таблица = Фокус ( "!Товары" );
      Выбрать ( "!ТоварыТовар [ 3 ]", таблица );

       

      Проверить ( Имя, Значение, Источник = неопределено, Тип = неопределено )

      Check ( Name, Value, Source = undefined, Type = undefined )

       

      Сравнивает значение поля с переданным значением. Если значения не совпадают, будет вызвано исключение.

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Поле.

      Значение: строка со значением, которое будет сравниваться с значением, хранящимся в проверяемом поле.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Примеры:

      Установить ( "Количество", 3 );
      Установить ( "Цена", 10 );
      Проверить ( "Сумма", "30.00" );
      
      // В пятой строке таблицы Начисления
      Проверить ( "#Начисления / Результат [ 5 ]", 1000 );

       

      ПроверитьСтатус ( Имя, Значение, Флаг = истина, Источник = неопределено, Тип = неопределено )

      CheckState ( Name, Value, Flag = true, Source = undefined, Type = undefined )

       

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

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Кнопка, КоманднаяПанель, Декорация, Поле, Группа, КнопкаКИ, ГруппаКИ, Таблица.

      Кроме этого, в параметр Имя можно передать несколько полей для проверки, разделяя их запятыми.

      Значение: строка, которая может принимать одно из следующих значений:

      1. Видимость (Visible)
      2. Доступность (Enable)
      3. ТолькоЧтение (ReadOnly)

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

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Примеры:

      // Указанные поля должны быть доступны, иначе, будет исключение
      ПроверитьСтатус ( "Часовой тариф, Время, Сумма проекта", "Доступность" );
      
      // Проверка колонок таблицы
      таблица = Фокус ( "!Товары" );
      ПроверитьСтатус ( "!ТоварыКоличествоУпаковок [2]", "Доступность", , таблица );

       

      ПроверитьШаблон ( Имя, Источник = неопределено, Тип = неопределено, Шаблон = неопределено )

      CheckTemplate ( Name, Source = undefined, Type = undefined, Template = undefined )

       

      Проверяет табличный документ.

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

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

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      В имени может быть задан полный путь к искомому полю. Примеры: Товары / Сумма, или Дополнительно / !Код.

      Применяется к объектам: Поле.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

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

      Пример:

      ПроверитьШаблон ( "!ОтчетРезультат" );

       

      ПроверитьОшибки ()

      CheckErrors ()

        Проверяет наличие сообщений. Если сообщения есть, Тестер выкинет исключение.

      Стоп ( Причина = неопределено )

      Stop ( Reason = undefined )

       

      Завершает выполнение сценария.

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

      Дождаться ( Имя, Таймаут = 3, Тип = неопределено )

      Waiting ( Name, Timeout = 3, Type = undefined )

      Булево

      Приостанавливает выполнение сценария до появления запрошенного объекта, например - окна.

      Имя: Строка заголовка формы. В строке могут использоваться символы * и ? для поиска по шаблону.

      Применяется к объектам: Форма, Окно.

      Таймаут: время в секундах, в течение которого Тестер будет ждать появления запрошенного объекта.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Метод возвращает Истина, если в течении отведенного времени объект был найден, Ложь в противном случае.

      Примеры:

      если ( не Дождаться ( "Помощник*" ) ) тогда
          Стоп ( "Окно с помощником должно было появиться" );
      конецесли;

       

      ПолучитьОкно ( Форма = неопределено )

      GetWindow ( Form = undefined )

      Тестируемое Окно Клиентского Приложения

      Возвращает объект типа ТестируемоеОкноКлиентскогоПриложения (TestedClientApplicationWindow) для переданной формы или текущий формы.

      Форма: объект типа ТестируемаяФорма. Если значение не задано, будет предпринята попытка получения окна для значения ТекущийОбъект.

      Примеры:

      форма = Здесь ( "Клиенты" );
      окно = ПолучитьОкно ();
      окно.Закрыть ();

       

      НайтиФорму ( Имя )

      FindForm ( Name )

      Тестируемая Форма

      Находит и возвращает форму по переданному заголовку.

      Применяется к объектам: Форма.

      Внимание! В отличие от метода Здесь, данная функция не устанавливает ТекущийОбъект

      Примеры:

      форма = НайтиФорму ( "Важная информация" );
      Нажать ( "ОК", форма );
      
      // Также, возможна более краткая запись, в этом случае, НайтиФорму будет вызвана неявно:
      Нажать ( "ОК", "Важная информация" );

       

      ПолучитьСсылки ( Форма = неопределено )

      GetLinks ( Form = undefined )

      Тестируемый Командный Интерфейс Окна

      Возвращает командный интерфейс формы.

      Форма: объект типа ТестируемаяФорма. Если значение не задано, будет предпринята попытка получения окна для значения ТекущийОбъект.

      Примеры:

      ГлавноеОкно.ВыполнитьКоманду ( "e1cib/command/Catalog.Партнеры.Create" );
      
      форма = Здесь ( "Партнер (соз*" );
      Установить ( "!НаименованиеПолноеКомпания", "Тестовый партнер" );
      Нажать ( "Поставщик" );
      Установить ( "!ГруппаДоступа", "Поставщики" );
      Нажать ( "!ФормаЗаписать" );
      
      // *********************************************
      // Создание контрагента
      // *********************************************
      
      Нажать ( "Контрагенты", ПолучитьСсылки () ); // Пример работы метода
      Здесь ( "Контрагенты*" );

      Пример на картинке:

      ПолучитьСообщения ()

      GetMessages ()

      Фиксированный массив

      Возвращает фиксированный массив сообщений активного окна.

      Метод может быть использован для анализа сообщений.

      Нажать ( "!ФормаПровести" );
      если ( ПолучитьСообщения ().Количество () = 0 ) тогда
      	Стоп ( "Ожидалось сообщение об ошибке" );
      конецесли;

       

      НайтиСообщения ( Шаблон )

      FindMessages ( Template )

      Массив

      Возвращает массив найденных сообщений.

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

      Использование символов  “*” и“?” имеет небольшое отклонение от стандартных правил регулярных выражений. Эти символы будут трансформированы в “[\s\S]+” и “[\s\S]” соответственно.

      Для дополнительной информации по регулярным выражениям см. http://userguide.icu-project.org/strings/regexp 

      Примеры:

      если ( НайтиСообщения ( "Не удалось провести*" ).Количество () = 0 ) тогда
      	Стоп ( "<Не удалось провести*> диалоговое окно должно быть показано" );
      конецесли;
      
      Нажать ( "OK", Forms.Get1C () ); // Закрыть стандартное 1С окно
      
      если ( НайтиСообщения ( "Списываемое количество превышает *" ).Количество () <> 1 ) тогда
      	Стоп ( "Сообщение об ошибке должно быть показано один раз" );
      конецесли;
      

       

      Пауза ( Секунды )

      Pause ( Seconds )

       

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

      Секунды: целое число секунд.

      Пауза ( 5 ); // Система будет здесь стоять 5 секунд

       

      ТекущаяВкладка ( Имя, Источник = неопределено, Тип = неопределено )

      CurrentTab ( Name, Source = undefined, Type = undefined )

      Тестируемая Группа Формы

      Возвращает текущую вкладку панели с вкладками.

      Имя: Идентификатор или Заголовок объекта. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      Применяется к объектам: Группа.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Тип: Отбор по типу. Доступны следующие строковые значения:

      1. Поле (Field)
      2. Группа (Group)
      3. Кнопка (Button)
      4. Таблица (Table)
      5. Декорация (Decoration)

      Если тип не задан, отбор по типу установлен не будет.

      Примеры:

      // Получаем заголовок текущей вкладки
      ТекущаяВкладка ( "!ГруппаСтраницы" ).ТекстЗаголовка;

       

      Далее ()

      Next ()

        Выполняет переход к следующему, согласно расположения элементов, полю.

      КСтроке ( Таблица, Колонка, Значение, ИзНачала = истина, Источник = неопределено )

      GotoRow ( Table, Column, Value, FromStart = true, Source = undefined )

      Булево

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

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

      Таблица: Идентификатор или Заголовок таблицы. Имя может задаваться с префиксом “!” или “#”. В этом случае, Тестер будет рассматривать имя как идентификатор искомого поля.

      Кроме этого, в параметр может быть передан сам тестируемый объект таблицы.

      В имени может быть задан полный путь к искомому полю. Примеры: ГруппаТовары / Товары, или Дополнительно / !ТаблицаИзделий.

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

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

      ИзНачала: булевое значение, задающее старт поиска. По умолчанию, значение Истина. Это означает, что метод вначале переместится в начало таблицы, и только потом начнет поиск. Если передать значение Ложь, поиск начнется с текущий строки таблицы.

      Источник: Тестируемый объект, строка с заголовком окна или Неопределено. Если значение не задано, тогда в качестве источника будет использоваться глобальная переменная ТекущийОбъект.

      Примеры:

      Здесь ( "Заказ поставщику *" );
      КСтроке ( "!Товары", "N", 3 ); // Перейдет в третью строку табличной части Товары (если есть как минимум три строки)
      
      // Переход по строкам связанных таблиц
      Здесь ( "Внутренние документы" );
      КСтроке ( "!Папки", "Наименование", "Служебные записки" );
      Пауза ( 1 );
      КСтроке ( "!Список", "Наименование", "О выделении персонального телефонного аппарата" );

      См. также Как перейти к строке таблицы по значениям нескольких колонок?

      Коммандос ( Действие, Активировать = истина )

      Commando ( Action, Activate = true )

       

      Выполняет навигационную команду системы по переданному строковому параметру.

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

      Действие: навигационная ссылка.

      Активировать: булевый флаг, по умолчанию Истина. Флаг отвечает за автоматическую установку открываемой формы – текущей. Фактически, если флаг Истина, метод после выполнения перехода по указанной навигационной ссылке, выполняет вызова метода Здесь. Важно учитывать особенность работы метода в случае использования флага ИгнорироватьОшибки = истина. Особенность заключается в том, что в случае неудачного перехода по навигационной ссылке (например, навигационная ссылка в параметре Действие задана неверно, или в процессе открытия формы объекта, возникла ошибка), платформа генерирует исключение в виде модального диалога. При этом, Тестер не может определить, является ли это окно целевой формой объекта, или результатом исключения его открытия. В любом случае, если параметр Активировать = истина, Тестер пытается активировать выведенное окно, и если это окно с ошибкой, генерируется системное исключение Объект не может быть найден (1С:Предприятие), что может вызвать конфуз при анализе проблемы. Таким образом, если вам требуется включать флаг ИгнорироватьОшибки = истина, следует рассмотреть установку параметра Активировать в значение Ложь (соответственно метод Здесь придется вызвать самостоятельно).

      Примеры:

      // Открывает стандартную форму списка
      Коммандос ( "e1cib/list/Справочник.Номенклатура" );
      
      // Открывает стандартную форму нового объекта
      Коммандос ( "e1cib/command/Справочник.Номенклатура.Создать" );
      
      // Открывает не параметризированную команду справочника
      Коммандос ( "e1cib/command/Справочник.Номенклатура.Команда.НовыйЭлемент" );
      
      // Открывает отчет
      Коммандос ( "e1cib/app/Отчет.ОстаткиТоваров" );
      
      // Открывает обработку
      Коммандос ( "e1cib/app/Обработка.ИмяМоейОбработки" );
      
      // Открывает общую команду
      Коммандос ( "e1cib/command/ОбщаяКоманда.ПанельОтчетовЗакупки" );
      
      // Открывает общую форму
      Коммандос ( "e1cib/data/ОбщаяФорма.Настройки" ); // Примечание: если при открытии формы возникнет ошибка, она не сможет быть обработана Тестером
      
      // Открывает журнал документов
      Коммандос ( "e1cib/list/DocumentJournal.ПередачиВозвратыТоваровМеждуОрганизациями" );

       

      ЗаписатьОшибку ( Текст )

      LogError ( Text )

       

      Выполняет добавление сообщения в журнал ошибок из кода сценария без остановки выполнения сценария.

      Текст: текст ошибки.

      Пример:

      попытка
          Вызвать ( "КакойтоТест", p );
      исключение
          ошибка = ОписаниеОшибки ();
          ЗаписатьОшибку ( ошибка );
      конецпопытки;

       

      МояВерсия ( Выражение )

      MyVersion ( Expression )

      Булево

      Определяет текущую версию приложения, сравнивает с переданной в выражении и возвращает результат сравнения.

      Выражение: Строка следующего формата: <Приложение> [<|>|=|<>|<=|>=] <Версия>.

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

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

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

      Внимание! Учет версий ведется в справочнике Приложения. Тестер не умеет получать версию запускаемого тестируемого приложения автоматически. Версии для каждого пользователя должны задаваться отдельно, в самом Тестере.

      Примеры:

      если ( МояВерсия ( "ERP2 = 2.2.1.102 - новый модуль ТМЗ" ) ) тогда
      	Ввести ( "!ДополнительныйКоэф", 1.5 );
      конецесли;
      
      если ( МояВерсия ( "Бух <= 3.1" ) ) тогда
      	// прочие поля в данных версиях недоступны
      	возврат;
      конецесли;
      

      ОтладкаСтарт ()

      DebugStart ()

       

      После выполнения данного метода, Тестер начнет пошаговое выполнение кода сценария. Фактически, данный метод является условным включением режима отладки сценария.

      Пример:

      если ( Взять ( "!Сумма" ) = 0 ) тогда
      	ОтладкаСтарт ();
      конецесли;
      Для глобального отключения всех точек останова, используйте служебное свойство Running в структуре Debug.

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

      если ( ИмяПользователя () = "НочнойТестер" ) тогда
      	Debug.Running = true;
      конецесли;
      
      ОтладкаСтарт (); // Будет игнорироваться для пользователя "НочнойТестер"

       

      СохранитьОкружение ( ИД )

      RegisterEnvironment ( ID )

       

      Сохраняет идентификатор тестового окружения во внутренней базе Тестера. Подробнее о подходе в организации тестового окружения читайте в разделе Структура сценария.

      ИД: Строка с идентификатором окружения.

      СозданоОкружение ( ИД )

      EnvironmentExists ( ID )

       

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

      ИД: Строка с идентификатором окружения.

      Снимок ( Заголовок = "", Сжато = неопределено )

      Screenshot ( Pattern = "", Compressed = undefined )

      ДвоичныеДанные

      Возвращает скриншот тестируемого приложения.

      Заголовок: Строка. Регулярное выражение для поиска главного окна тестируемого приложения. Если параметр не задан, Тестер будет искать приложение по заголовку, заданному в профиле тестируемого приложения:

      Подробнее о регулярных выражениях читайте на сайте https://www.regular-expressions.info/

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

      Дополнительную информацию можно получить в разделе Формирование скриншотов.

      ВСтудию ( Текст )

      VStudio ( Text )

       

      Выводит сообщение в список сообщений Тестера, а также в панель Output текстового редактора Visual Studio Code.

      Текст: Строка с текстом сообщения.

      Подробнее см. в разделе Интеграция с Visual Studio Code.

      Пример:

      1С:Предприятие:

      Visual Studio Code:

      УстановитьПриложение ( Имя )

      PinApplication ( Name )

       

      Устанавливает в тестируемом окружении текущее приложение.

      Имя: Строка с идентификатором приложения согласно справочника Приложения.

      Данный метод может быть использован в делегируемых сценариях (см. Механизм заданий) для задания агенту текущего приложения, с которым ему нужно работать.
      Например, вы тестируете два приложения. Для каждого приложения у вас разрабатывается свой набор тестов. Также, у вас есть агент, который по заданию запускает наборы тестов для данных приложений.
      Чтобы агент знал, с каким приложением он работает, ему нужно установить такое приложение текущим, перед выполнением сценариев. Такая необходимость связана с тем, что часть разрабатываемых тестов может быть не привязана к конкретному приложению (например, тестирование общих механизмов).

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

      УстановитьВерсию ( Версия, Приложение = неопределено )

      SetVersion ( Version, Application = undefined )

       

      Устанавливает текущую версию приложения.

      Версия: Строка с названием существующей версии приложения. Версии создаются в справочнике Приложения. Если версия не будет найдена, будет вызвано исключение.

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

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

      НовоеЗадание ( Агент, Сценарий, Приложение = неопределено, Параметры = неопределено, Компьютер = неопределено, Комментарий = неопределено )

      NewJob ( Agent, Scenario, Application = undefined, Parameters = undefined, Computer = undefined, Memo = undefined )

       

      Создает делегированное задание. Подробнее см. Механизм заданий

      Агент: Строка с именем пользователя-агента, который будет выполнять задание.

      Сценарий: Строка с идентификатором сценария. Например: Справочники.Номенклатура.ТестСоздания.

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

      Параметры: Строка неограниченной длины для передачи параметров заданию. Параметры затем могут использоваться в сценариях, запускаемых по заданию. Для передачи объектов, можно использовать строку в формате JSON. Для преобразования объекта (например, структуры) можно использовать функцию Conversion.ToJSON ( МояСтруктура ).

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

      Комментарий: Произвольная дополнительная информация.

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

      Метод доступен как в клиентском, так и серверном контексте.

      ПерейтиВКонсоль ()

      GotoConsole ()

       

      Метод перенаправляет текущую сессию в основную консоль сервера.

      Метод имеет смысл вызывать в сценариях, выполняемых на удаленных серверах, где тестирование производится по запросу или регламенту. Главную проблему, которую решает данных метод – это формирование скриншотов на удаленных серверах. Подробнее см. Почему скриншот формируется в виде черного квадрата?

      Заявить ( Что, Детали = "" )

      Assert ( What, Details = "" )

       

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

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

      В случае, если проверяемое в выражении условие не выполняется, Тестер генерирует исключение с выдачей соответствующего сообщения; выполнение сценария прекращается.

      Что: Проверяемое значение.

      Детали: Строка с деталями проверки, которая будет дополнять сообщение об ошибке в случае невыполнения текучего условия.

      Текучие функции
      Русский Английский Дополнительно
      ЭтоИстина () IsTrue ()

      Категория функций, для проверки значения на говорящее за себя условие.

      Например:

      // "0 + " для автоматического получения числа из поля с суммой
      сумма = 0 + Взять ( "!СуммаСНДС" );
      
      // Первый вариант
      Заявить ( сумма ).Равно ( 1500 );
      
      // Второй вариант
      Заявить ( сумма = 1500 ).ЭтоИстина ();

       

      ЭтоЛожь () IsFalse ()
      Равно ( Значение ) Equal ( Value )
      НеРавно ( Значение ) NotEqual ( Value )
      Больше ( Значение ) Greater ( Value )
      БольшеИлиРавно ( Значение ) GreaterOrEqual ( Value )
      Меньше ( Значение ) Less ( Value )
      МеньшеИлиРавно ( Значение ) LessOrEqual ( Value )
      Заполнено () Filled () Стандартная проверка заполненности значения.
      Пусто () Empty () Противоположность функции Заполнено.
      Существует () Exists () Проверяет, что значение не является Неопределено и не Null.

      ЭтоNull ()

      ЕстьNull ()

      IsNull () Проверка на Null.
      ЭтоНеопределено () IsUndefined () Проверка на Неопределено.
      Между ( Старт, Финиш ) Between ( Start, Finish ) Проверка на вхождение значения в диапазон.
      Содержит ( Значение ) Contains ( Value )

      Проверка наличия Значение в передаваемом методу Что, объекте.

      Если объектом является строка, функция будет искать подстроку.

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

      Примеры:

      // Строка
      покупатель = Взять ( "!Покупатель" );
      Заявить ( покупатель ).Содержит ( "LTD" );
      
      // Массив
      список = новый Массив ();
      список.Добавить ( Взять ( "!Статус1" ) );
      список.Добавить ( Взять ( "!Статус2" ) );
      список.Добавить ( Взять ( "!Статус3" ) );
      Заявить ( список ).Содержит ( "Одобрено" );

       

      Вмещает ( Значение )

      ИмеетДлину ( Значение )

      Has ( Value )

      Проверяет переданное значение на длину или размер.

      Если в качестве параметра передана строка, будет произведена проверка длины строки.

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

      Не_ () Not_ ()

      Метод-префикс для реверса следующего за ним условия.

      Например:

      Заявить ( истина ).Не_ ().ЭтоЛожь ();

       

      Примеры:

      течьНаКлиенте ();
      течьНаСервере ();
      
      &НаКлиенте
      Процедура течьНаКлиенте ()
      
      	Заявить ( 2 ).Равно ( 1 + 1 );
      	Заявить ( 2 ).Не_ ().Равно ( 3 ).Равно ( 2 ).Не_ ().Равно ( 4 );
      	Заявить ( 2 ).Больше ( 1 );
      	Заявить ( 2 ).Заполнено ();
      	Заявить ( неопределено ).Не_ ().Заполнено ();
      	Заявить ( неопределено).Пусто ();
      	Заявить ( 0 ).Существует ();
      	Заявить ( null ).Не_ ().Существует ();
      	Заявить ( 2 ).Не_ ().Между ( 10, 15 ).Между ( 0, 5 );
      	Заявить ( "Строка", "Содержание в строке" ).Содержит ( "к" ).Не_ ().Содержит ( "2" );
      	Заявить ( новый Структура ( "п1, п2, п3", 1, 2, 3 ), "Содержание в структуре").Содержит ( 2 );
      
      	массив = новый Массив (); 
      	массив.Добавить ( 1 );
      	массив.Добавить ( 3 );
      	массив.Добавить ( 5 );
      	Заявить ( массив).Вмещает ( 3 ).Не_ ().Вмещает ( 5 );
      
      КонецПроцедуры
      
      &НаСервере
      Процедура течьНаСервере ()
      
      	Заявить ( 2 ).Равно ( 1 + 1 );
      	Заявить ( 2 ).Не_ ().Равно ( 3 ).Равно ( 2 ).Не_ ().Равно ( 4 );
      	Заявить ( 2 ).Больше ( 1 );
      	Заявить ( 2 ).Заполнено ();
      	Заявить ( неопределено ).Не_ ().Заполнено ();
      	Заявить ( неопределено).Пусто ();
      	Заявить ( 0 ).Существует ();
      	Заявить ( null ).Не_ ().Существует ();
      	Заявить ( 2 ).Не_ ().Между ( 10, 15 ).Между ( 0, 5 );
      	Заявить ( "Строка", "Содержание в строке" ).Содержит ( "к" ).Не_ ().Содержит ( "2" );
      	Заявить ( новый Структура ( "п1, п2, п3", 1, 2, 3 ), "Содержание в структуре").Содержит ( 2 );
      
      	массив = новый Массив (); 
      	массив.Добавить ( 1 );
      	массив.Добавить ( 3 );
      	массив.Добавить ( 5 );
      	Заявить ( массив).Вмещает ( 3 ).Не_ ().Вмещает ( 5 );
      
      КонецПроцедуры

       

      ХронографСтарт ()

      RecorderStart ()

       

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

      Структура содержит следующие поля:

      • Сценарий (Scenario). Ссылка на справочник Scenarios или Versions
      • Модуль (Module). Ссылка на справочник Modules

      Значения полей структуры могут быть использованы для очистки хронографа, см. метод ХронографОчистить.

      Однажды активированный хронограф остается активированным в течение всей тестовой сессии или до первого вызова ХронографСтоп. Вложенность вызовов ХронографСтартХронографСтоп не поддерживается.

      ХронографСтоп ()

      RecorderStop ()

        Останавливает хронограф. Очистка структуры Хронограф не производится.

      ХронографОчистить ( Сценарий = неопределено, ПоДату = неопределено, Сессия = неопределено )

      RecorderClean ( Scenario = undefined, DateTo = undefined, Session = undefined )

       

      Производит очистку записей хронографа по переданным параметрам.

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

      ПоДату: Дата, по которую включительно будут удалены записи. Если значение не задано, будут удалены записи за весь период.

      Сессия: Ссылка на справочник Sessions. Если значение не задано, будут удалены записи текущей сессии пользователя.

      Примеры использования:

      // Очищает все записи моей текущей сессии
      ХронографОчистить ();
      
      // Очищает все записи текущего сценария.
      // Внимание! Метод ХронографСтарт () должен быть предварительно
      // вызван для определения структуры Хронограф
      ХронографОчистить ( Хронограф.Сценарий );

       

      ПрогрессПоказать ()

      ProgressShow ()

       

      Метод производит включение отображения диалогового окна с прогрессом выполнения сценария.

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

      ПрогрессСкрыть ()

      ProgressHide ()

       

      Метод отключает отображение окна прогресса выполнения сценария.