mock server что это

Русские Блоги

Применение Mock в модульном тесте Java

Перепечатано по адресу: https://blog.csdn.net/zuozewei/article/details/84892008

Каталог статей

введение

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

Определение слова mock

вОсновы производительности говорят о тестировании производительности общего интерфейса.В этой статье мы кратко представили Mock, а в этой статье подробно рассматривается концепция Mock.
В процессе тестирования интерфейса для некоторых объектов, которые нелегко построить или получить, мы часто заменяем их виртуальным объектом для тестирования. В конкретном процессе тестирования мы часто сталкиваемся с ситуациями, когда нам нужно моделировать данные или интерфейсы. Из-за проблем со средой или сложности системы нам необходимо использовать фиктивные методы для моделирования данных.
Цитата из определения Mock из «Белой книги по тестированию интерфейса» Taobao:

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

Классификация моков

Эти два сценария составляют большую часть объема использования Mock.

Издеваться над объектом

Здесь используется пример Mockito


Общие действия по использованию Mockito:

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

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

Mock Server

На следующем рисунке поясняется расположение и функции Mock Server:

Общий Mock-сервер

резюме

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

Источник

Мок-сервер для автоматизации мобильного тестирования

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

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

Чтобы не трогать код реального проекта (под NDA), для наглядности дальнейшего изложения я создал простой REST-клиент под Android, позволяющий отправлять на некий адрес HTTP-запросы (GET/POST) с необходимыми мне параметрами. Его-то мы и будем тестировать.
Код приложения-клиента, диспатчеров и тестов можно скачать с GitLab.

Какие существуют варианты?

Подходов к мокированию в моем случае существовало два:

Выбор мок-сервера

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

Разбираем принцип работы

Текущая версия okhttpmockwebserver позволяет реализовать несколько сценариев работы:

Очередь ответов

Простейшая реализация мок-сервера – очередь ответов. До теста я определяю адрес и порт, где будет развернут мок-сервер, а также тот факт, что он будет работать по принципу очереди из сообщений – FIFO (first in first out).

Далее запускаю мок-сервер.

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

Реализация диспатчера

Диспатчер – это набор правил, по которым работает мок-сервер. Для удобства изложения я создал три разных диспатчера: SimpleDispatcher, OtherParamsDispatcher и ListingDispatcher.

SimpleDispatcher

Логика в этом примере простая: если приходит GET, я возвращаю сообщение, что это GET request. Если POST, возвращаю сообщение о POST request. В иных ситуациях возвращаю пустой запрос.

Исходники тестов с SimpleDispatcher можно найти в репозитории.

OtherParamsDispatcher

В данном случае я демонстрирую несколько вариантов условий.

За примерами тестов рекомендую обратиться к репозиторию.

ListingDispatcher

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

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

Ради эксперимента я заменил стаб на POST:

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

Request Verifier

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

Итоги

В целом инструмент (okhttpmockwebserver) мне понравился, и я использую его на большом проекте. Безусловно, есть некоторые мелочи, которые я хотел бы изменить.
Например, мне не нравится, что приходится стучаться по локальному адресу (localhost:8080 в нашем примере) в конфигах своего приложения; возможно, я еще найду способ все настроить так, чтобы мок-сервер отвечал при попытке отправить запрос на любой адрес.
Также мне не хватает возможности переадресации запросов – когда мок-сервер отправляет запрос дальше, если у него нет для него подходящего стаба. В данном мок-сервере такого подхода нет. Впрочем, до их внедрения и не дошло, поскольку на данный момент в “боевом” проекте не стоит такой задачи.

Источник

Моки без лишней мороки с mswjs+faker.js

Привет, Хабр! Меня зовут Виктор, я фронтенд-работчик в Admitad. Моя команда делает личный кабинет клиентов. Недавно я в очередной раз столкнулся с типичной проблемой: для создания нового функционала фронтенд и бэкенд нужно было реализовывать параллельно. Но как делать фронт, не имея 100% рабочих эндпойнтов на бэкенде? Сегодня я расскажу о том, какие подходы применял, и разберу их плюсы и минусы.

Читайте также:  какой лимит перевода с карты сбербанка моментум

О проблеме

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

Как организовать получение mock-данных?

Для решения проблемы есть несколько вариантов. Начнем с самого популярного.

Пишем сервер на node.js

Мы всегда можем написать свой mock-server на node.js используя такие фреймворки, как express или koa.

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

О более продвинутом можно почитать тут.

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

Используем внешние API сервисы

Уверен, многие знакомы с таким сервисом готовых API, как jsonplaceholder.typicode.com, в котором есть как готовые энднпойнты, например, /posts, /comments. так и возможность добавлять свои, причем, либо создав в репозитории своего проекта файл db.json с фейковыми данными, либо с помощью приложения Mockend. Главный, на мой взгляд, минус заключается в том, что такой подход не позволяет использовать например POST-запросы.

Используем Mock Service Worker + Faker

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

Итак, наши инструменты:

Работает всё следующим образом: настраиваем service worker, который будет обрабатывать наши сетевые запросы и возвращать сгенерированные нами фэйковые данные, пока бэкенд в разработке. Таким образом работа двух команд может вестись параллельно. А когда бэкенд будет готов, достаточно будет сделать сборку без флага, запускающего mock-сервис.

Две основные концепции с которыми работает MSW, это:

Обработчики запросов

MSW содержит в себе два набора методов для создания обработчиков для работы с API: rest и graphql.

Источник

Использование mock при интеграции с внешним API

Тестирование интеграции с API

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

Есть много разных вариантов API:

Есть мастодонты – Google, Яндекс – у них много разных сервисов, с которыми можно интегрироваться. Например, получение переводов, генерация и чтение текстов, прогнозы погоды.

Часто приходится интегрироваться с «Почтой России» или OZON.RU – если ваша компания занимается перевозками или отправкой товаров.

С Telegram – если надо отправлять или получать данные и писать ботов.

И, конечно, наши государственные сервисы: например, ФНС, если вам нужно получать данные о контрагентах.

У всех этих вариантов есть нечто общее:

Клиент-серверное взаимодействие, когда вы от себя отправляете данные, а все обрабатывается на стороне сервиса.

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

Используется немного кэширования.

Формат ответа – обычно HTML, XML, JSON либо бинарные файлы (если вы что-то получаете в виде картинок или pdf-документов).

Проблемы тестирования

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

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

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

Большая проблема – скорость ответов. Зависит от того, какая нагрузка на сервере, которым вы пользуетесь, сколько до вас идет ответ.

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

Еще есть проблема: можно увлечься, и вместо того, чтобы тестировать, как ваше приложение взаимодействует с API, начать тестировать API. Вы думаете: «А что будет, если я отправлю такой запрос, а если такой, а если здесь пробел поставлю?» И получается, что вместо того, чтобы придумать сценарий, как вы будете взаимодействовать с сервером, вы смотрите, как ответит сервер.

Методы решения проблем

Какие есть методы решения проблем?

Самый простой вариант – вам предоставят тестовый стенд. Вам выделяют отдельную область, в которой вы будете тестировать свои алгоритмы.

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

Следующий вариант – написать свой сервер.

Все программисты, если что-то не работает на стороне, начинают писать свое. Делаем небольшой сервер – берем Python или OneScript.Web – и пишем небольшие заглушки. Мы знаем, какие запросы отправляем, готовим под них ответы.

В чем здесь проблема? Его надо писать. Это будет ваше отдельное приложение, которое надо поддерживать.

Следующий вариант – использовать специальные mock-сервера (заглушки).

Для них все равно нужно будет готовить данные.

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

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

Мы разберем мокирование.

Мокирование

Мокирование от английского mock – «заглушка». Выглядит это следующим образом.

Читайте также:  что делать если заклинило шею и больно поворачивать голову в левую сторону

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

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

Заглушка присылает ответы, а тест верифицирует: правильные ли данные получила система.

Вариантов таких мок-серверов много, перечислю самые популярные.

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

SoapUI – достаточно мощное решение, там есть запись ваших запросов, их воспроизведение, упаковка в сценарии. Достаточно популярное решение для мокирования.

Есть сервис МоckServer. С ним я еще не разобрался, он достаточно сложный.

И есть JSON-Server – легкое решение, в нем есть база данных, основанная на JSON. Он умеет сохранять данные и преобразовывать.

Но я вам хочу рассказать про работу с WireMock.

WireMock – запуск, возможности, управление

Что такое WireMock?

WireMock – приложение на Java, что уже хорошо. Значит, вы сможете его запускать и на Windows, и на Linux.

Он умеет работать в режиме JUnit, когда вы пишете тесты на Java, и Standalone – как отдельно запускаемое приложение. С 1С я его чаще использую как Standalone.

Он очень хорошо управляется через HTTP-запросы. Когда вы его как Standalone подняли, он управляется, отправляя запросы на нужный адрес.

Все настройки он хранит в JSON-формате – это очень удобно, потому что JSON хорошочитаемый, его удобно смотреть при code-review.

У него есть функция записи и воспроизведения – чуть позже расскажу, что это такое.

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

Чтобы было понятнее – давайте разберем конкретную задачу.

Практика

Наша задача – сделать погодный виджет для Бухгалтерии 3.0. Я достаточно часто встречал такие обработки на Инфостарте – видимо, многие клиенты хотят знать погоду, не выходя из 1С.

Мы выведем на главной странице Бухгалтерии 3.0 текущий прогноз погоды и постараемся максимально закрыть это тестами.

Реализация выглядит вот так – это расширение, которое я нашел на Инфостарте в публикации //infostart.ru/public/801039/. Оно выводит погоду – сейчас +18 градусов.

Давайте накроем его код тестом.

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

Насколько это будет стабильный тест? С утра у нас было +7, днем стало +15, два часа назад пошел дождь, но теперь светит солнце. Соответственно, тест будет совершенно нестабилен – каждый раз, когда меняется погода, тест будет падать.

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

Подготовка

Первым делом, нужно провести подготовку.

Настроить запуск 1С в режиме тестирования.

Научиться перенаправлять запросы – чтобы запросы отправлялись не к внешнему сервису, а к нашему.

Подготовить набор ответов.

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

Теперь насчет подготовки мокированных ответов.

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

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

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

Шаблон выглядит вот так: здесь URL запроса и ответ.

Содержание большого JSON-ответа можно упаковать в отдельный файлик – его адрес будет указан в свойства bodyFileName.

Вот так выглядит этот JSON-файл ответа.

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

Макеты

Давайте подробнее разберемся, что такое макет.

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

Самое первое, что есть в шаблонах – какой HTTP-метод мы используем.

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

Дальше мы разбираем, куда уходит наш запрос.

Первый вариант – использовать свойство url, которое описывает полное соответствие, включая все параметры. Мы прямо говорим, что если мы делаем GET-запрос по такому-то URL – возвращай ответ. Это не очень удобно, потому что в коде могут поменяться местами параметры, некоторые параметры будут являться обязательными или необязательными.

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

И совсем простой вариант – с помощью свойства urlPath указывать только начальный путь. Чаще всего я использую именно этот вариант, когда указываю, что запрос будет по такому-то URL, а потом отдельно обрабатываю параметры запроса через свойство queryParameters.

Есть несколько вариантов обработки параметров:

equalTo – это точное соответствие, когда вы говорите, чему должен быть равен этот параметр;

matches – регулярное выражение, которому этот параметр должен соответствовать.

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

С помощью свойства bodyPatterns есть возможность обрабатывать тело запроса. В зависимости от того, какой запрос вы обрабатываете, можно использовать:

Читайте также:  какой макроэлемент входит в состав гемоглобина эритроцитов

XPath-язык – свойство matchesXPath;

JSONPath – свойство matchesJsonPath;

или описывать полное совпадение тела запроса через свойства equalToXml и equalToJson.

Это все, что касается шаблона запроса.

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

Вы можете готовить динамические ответы:

указывать дату в определенном формате;

разбирать входящие параметры, если это требуется;

там есть конкатенация строк и т.д.

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

Stateful

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

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

WireMock позволяет это реализовать:

у него есть понятие сценария;

каждый сценарий должен находиться в определенной стадии;

эти стадии можно переключать как прямым запросом по HTTP, так и самим сценарием.

Например, здесь на слайде указан сценарий «To do list», и текущее состояние у него стартовое (“requiredScenarioState”: “Started”).

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

Нам потребуется два шаблона:

один стартовый (“requiredScenarioState”: “Started”),

другой я назвал bad (“requiredScenarioState”: “bad”) – сейчас объясню, почему.

Логика такая – когда наш сервер стартует, он находится в стартовом состоянии и подает нужный ответ.

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

Как это будет выглядеть в тесте? Мы указываем, что работаем со сценарием Weather.

Прямо в коде явно переключаем его состояние – тогда через 30 секунд у нас меняется погода на виджете.

Аварийные ситуации – низкая скорость, обрыв, мусор

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

Лучше постараться обработать эти аварийные ситуации – повторно отправить запрос или подсказать пользователю.

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

Как это можно реализовать с помощью мокирования?

Первое – задержка ответа. Прямо в шаблоне можно указать, что нам потребуется какая-то задержка.

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

Есть вариант показать, что это уже случайная величина на каждый запрос.

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

Еще интересный вариант, что делать, если вам пришел вообще невалидный ответ сервера:

вам может прийти пустой запрос;

может прийти мусор в ответе – когда вначале был json, а потом абракадабра;

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

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

Если вы перехватите такую ошибку, 1С это более-менее переваривает.

Интересный вариант реализации – как протестировать обрыв связи. Реализуется как раз цепочками состояний.

есть стартовое состояние – Started;

дальше мы получаем валидное состояние с погодой – Good;

переключаем наш сценарий запросом CONNECTION_RESET_BY_PEER на состояние Conn_reset («Оборвать соединение»);

и снова переключаем на хорошее – Good.

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

Резюме

Как итог всего этого – вы получаете:

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

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

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

Все это позволит вам повышать качество ваших продуктов.

Полезные ссылки

Накину чуть-чуть полезных ссылок, что можно почитать подробнее:

Статья на Инфостарте //infostart.ru/public/1014870/ про использование SoapUI в качестве заглушек.

Мой демо-стенд: https://github.com/KrapivinAndrey/infostart2020-DevOps1c-Mockdemo – можете зайти и посмотреть все сценарии, которые я вам показал. Плюс еще парочка реализованных. Возьмите и попробуйте их локально позапускать, посмотреть, как это все устроено.

Вопросы

Где взять шаги для фич, чтобы работать с WireMock?

Шаги можно взять там же, у меня в репозитории

Пробовали ли вы использовать OneScript.Web в качестве мок-сервера?

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

Как изменяется состояние сервера? Это какая-то опция в командной строке его запуска?

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

Непонятно, в каком формате смотреть результаты тестов.

Результаты тестов смотреть в привычном формате – Allure, Junit. Как обычно, мы проверяем результаты нашего тестирования в фреймворке тестирования – например, Vanessa ADD. Мы не тестируем API, мы тестируем поведение нашей системы – мы отправляем запрос, ожидаем, что поле будет иметь такое значение. Если это не так, очевидно, что тест провален.

Данная статья написана по итогам доклада (видео), прочитанного на онлайн-митапе «DevOps в 1С: Тестирование и контроль качества решений на 1С». Больше статей можно прочитать здесь.

Источник

Сказочный портал