что такое data driven тест кейс

Data Driven Testing

Добрый день уважаемые жители Хабра!

Работая на текущем проекте, я столкнулся с проблемой однотипных данных и необходимостью протестировать разные http вызовы над одними и теми же данными. Проект разрабатывается на django/django-rest-framework/python3.5. Поначалу я начал использовать этот движок для упрощения тестирования django-rest-framework (django-rest-assured).

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

А есть ли реальная необходимость в этом?

К примеру, возьмем объект машина, стоит цель продать машину, какие действия могут быть выполнены над ней и какие типы запросов могут быть в отношении этого объекта (машина):

Но разные http запросы. Я согласен, что может быть не совсем удачный пример с машиной, ибо http запросами не оценить стоимость восстановления машины… Да и понятно же что много из этих данных могут быть возвращены при GET запросе касательно этой машины (и дополнительные http запросы могут не потребоваться), но предположим это не так. И тут возникает проблема: у нас одна машина, но куча тестов для каждой из операций над этой машиной. Почему бы не сгруппировать все эти тесты в один набор тестов но над одним ресурсом.

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

Сразу замечу, почему я здесь привожу ссылку с , я использую в easytest движке open api схему для генерации фикстур для запроса и тд и тп.
И в openapi схеме ссылка для detail запросов связанных с конкретных ресурсом генерируются как:

И что дальше?

Затем, имея open api схему, мы можем:

Теперь по порядку о том как все работает:

Как понять что ошибка произошла?

На сегодняшний момент, в случае падения теста происходит вывод того что упало, на каком эндпоинте, и traceback exceptionа в консоль (терминал) в красном цвете. И если хоть один тест упал, то падает весь тест test_resources с следующим сообщением:

Automatic test of endpoints has been failed

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

И да, решение не идеальное

Источник

Объясните пожалуйста что такое test-case data-driven с примерами

Объясните пожалуйста что такое test-case data-driven с примерами!

Мне понравились примеры из книги Романа Савина «Тестирование дот ком», часть 1, глава «Искусство создания тест кейсов», раздел «Тест-кейсы, управляемые данными». Они очень простые, но при этом и не игрушечные. Книгу эту легко найти)

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

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

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

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

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

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

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

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

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

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

Спасибо!А все тест-кейсы являются управляемыми данными или нет?

Почти под все тесты в принципе можно подвести эту практику. Если это необходимо.

Почти под все тесты в принципе можно подвести эту практику. Если это необходимо.

Мне понравились примеры из книги Романа Савина «Тестирование дот ком», часть 1, глава «Искусство создания тест кейсов», раздел «Тест-кейсы, управляемые данными». Они очень простые, но при этом и не игрушечные. Книгу эту легко найти)

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

Источник

Что такое data driven тест кейс

Без какой части тест-кейс никак не может обойтись?

Вопрос номер 2

Для чего в тест-кейсе нужны шаги?

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

Вопрос номер 3

Два вида исхода исполнения тест-кейса. К какому исходу мы, как тестировщики, стремимся?

Каждый завершенный тест-кейс дает один из двух исходов (результатов):
Положительный исход (PASS), если фактический результат исполнения тест-кейса равен ожидаемому.
Отрицательный исход (FAIL) если фактический результат исполнения тест-кейса НЕ равен ожидаемому.

Вопрос номер 4

Вопрос номер 5

Вопрос номер 6

УНИКАЛЬНЫЙ ID(Unique ID)
ID должен быть уникальным в пределах не только документа, содержащего тест-кейс, но и всего департамента качества. Необходим для ведения статистики по тест-кейсам, обновления, удаления или переноса в другой документ. Что бы ничего не путалось.

ПРИОРИТЕТ ТЕСТ-КЕЙСА (Test Case Priority)
Используется для определения важности тест-кейса. Помогает определить очередность выполнения тест-кейсов.

ИДЕЯ (IDEA)
Это описание конкретной вещи, проверяемой тест-кейсом.

ПОДГОТОВИТЕЛЬНАЯ ЧАСТЬ(SETUP and ADDITIONAL INFO)
Все данные, которые могут понадобиться при выполнении тест-кейса, собранные в одном месте.

Вопрос номер 7

Вопрос номер 8

Вопрос номер 9

Вопрос номер 10

Вопрос номер 11

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

Ответ из комментариев
Формальные недостатки, не позволяющие тест-кейсам быть белыми и пушистыми.
Если я правильно понял вопрос, то речь идет о поддерживаемости тест-кейса.
Поддерживаемость тест-кейса — это легкость и удобство, с которыми он может быть изменен.
Я не понял вопрос, стоит уточнить у автора.

Вопрос номер 12

Вопрос номер 13

Ожидается ли, что тестировщик изменит тест-кейс, написанный лишь на основании спека, без знакомства с реально написанным ПО?
Никто не ожидает, что тест-кейсы будут на 100% «работать» сразу после написания. Дело в том, что они создаются на основании опека (или, как это часто бывает, на основании устного пожелания начальника), и так как мы физически не видим функциональностей этого опека (код еще не написан), то многие вещи нужно в буквальном смысле представить себе. Кроме того, как мы уже видели, сами спеки имеют баги и спек может быть изменен без ведома тестировщика.

Ответ из коментариев
Да, ожидается, что тестировщик изменит тест-кейс, написанный лишь на основании спека, без знакомства с реально написанным ПО.

Вопрос номер 14

Вопрос номер 15

Приведите атрибуты шапки тест-комплекта.
Author — автор тест-кейсов.
Spec ID — номер (или иной уникальный ID) спека.
Priority — приоритет тест-комплекта (например, от 1 до 4), обычно соответствующий приоритету спека.
Producer — продюсер, написавший спек.

Developer — программист, пишущий код в соответствии со спеком.

Добавленно из комментариев
Overview — вкратце рассказывается, чему посвящен этот тест-комплект.
GLOBAL SETUP and ADDITIONAL INFO — здесь мы говорим о повторяющихся вещах, которые будем использовать в более чем одном тест-кейсе, и вообще о любой другой полезной информации для всего тест-комплекта.

Вопрос номер 16

Состояния тест-кейса.

состояние — «Новый» (New).
Это первая редакция тест-кейса:
«Created on: 11/17/2003 by 0. Тарасов».

состояние — «Измененный» (Modified).
Модификации, как правило, связаны с изменением спека, затрагивающего этот тест-кейс, или с улучшением тест-кейса, например, для удобства в поддержке:
«Modified on: 11/26/2003 by И.Новикова».

состояние — «Более недействителен» (Retired).

Вопрос номер 17

Вопрос номер 18

Вопрос номер 19

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

Источник

Data-Driven тесты в MS-Test для модульного и приёмочного тестирования

что такое data driven тест кейс. image loader. что такое data driven тест кейс фото. что такое data driven тест кейс-image loader. картинка что такое data driven тест кейс. картинка image loader.Я бы сразу хотел подчеркнуть тот факт, что мир модульных тестов и мир приёмочных тестов через пользовательский интерфейс – это очень разные миры: со своими законами, разными возможностями и ограничениями. И если мир модульных тестов работает на покрытие каждой части приложения по отдельности и в изоляции, то тесты через пользовательский интерфейс – это эмуляция работы пользователя с системой, по большей части через нажатие кнопок и набор текста, которые в итоге сливаются в более крупные бизнес-сценарии.

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

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

Data-Driven подход в мире модульных тестов

Предположим, у нас есть метод int ConvertToNumber(string input), который на вход принимает строку с числом и возвращает это же число, только в целочисленном типе.

Пусть мы напишем один позитивный тест, (который приносит радость) например, для input = “3” и проверим, что результат будет тоже 3.

Что еще? Конечно же, граничные значения и классы эквивалентности: “-1”, “0”, “MaxInt”, “-(MaxInt)”.
Хорошо, а что если на вход попадет десятичная дробь? А если строка начинается с цифры, за которой следуют символы?

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

Обратите внимание, что разные языки программирования обрабатывают такие ситуации по-разному. Например, JavaScript в результате операции < “10” + 1>вернет строку “101”, а в результате < “10” — 1>будет число 9. А Perl скажет: 11 и 9 соответственно. Но, отсутствие «истинного» ответа совсем не мешает нам самостоятельно придумать правильные варианты поведения и сказать, что отныне – это есмь истина, и высечь эту истину модульными тестами в камне.

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

Пример data-driven модульного теста на Ms-Test

Для наглядности примера, в реализации ConvertToNumber, я не буду использовать Convert.ToInt32() –это было бы слишком просто. Вместо этого, предложу свою реализацию:

К сожалению, в Ms-Test пока нет возможности задать входящие и ожидаемые значения непосредственно в коде, при помощи атрибутов. Зато, есть альтернатива – использовать источники данных. И в качестве такого источника, вы не поверите, будем использовать Excel-файл.

что такое data driven тест кейс. image loader. что такое data driven тест кейс фото. что такое data driven тест кейс-image loader. картинка что такое data driven тест кейс. картинка image loader.

Главное – не забыть выделить нужный фрагмент и форматировать его как «Таблица с заголовком». Иначе – магия не будет работать.

Тогда модульный тест с реализаций соединения с Excel-таблицей и чтением данных будет выглядеть следующим образом:

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

что такое data driven тест кейс. image loader. что такое data driven тест кейс фото. что такое data driven тест кейс-image loader. картинка что такое data driven тест кейс. картинка image loader.

А чтобы добавить новый тест – достаточно добавить новую строку в Excel. И в код лезть не нужно, чтобы посмотреть, что же конкретно тестами покрыто, а что – нет.

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

Прошу заметить, что даже на моей низко производительной машине, все 14 тестов прошли за менее чем за 1 секунду.

Не знаю как вы, но я был просто впечатлен такими возможностями и наглядными результатами.
Примечание: Для того, чтобы всё заработало, не забудьте скопировать файл matrix.xlsx в корень диска C:\

Data-Driven подход в мире тестирования через пользовательский интерфейс

К огромному моему сожалению, после того, как я взялся за UI-тесты с использованием Selenium WebDriver – моему восхищению от мега-крутой фичи Ms-Test пришёл конец.

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

Следовательно, с учетом всех возможных оптимизаций, один UI-тест может идти от 30-ти секунд до десятков минут. Всё зависит от сложности сценария.

Например, если предположить, что 1 из 14 data-driven тестов идет одну минуту – то весь набор пройдет за 14 минут.
А теперь представьте себе, что один тест упадёт по какой-то причине, например из-за того, что кнопочка на странице не успела появиться…
Не беда, скажете вы, ведь можно исправить и прогнать только упавшие тесты.
Нет. Ms-Test считает пачку data-driven тестов как один тест. Следовательно, чтобы перепрогнать 1 тест – придётся запускать все 14 вновь. И не факт, что те тесты, которые проходили раньше – вдруг не упадут. А в случае отладки, придётся не просто ставить точку останова, а настраивать условную точку останова: Visual Studio это позволяет… но, это требует дополнительных усилий и затрат времени.

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

Решение задачи: «цикл через наследование»

Для решения задачи, необходимо добавить в проект 2 файла: TestBase.cs и TestRows.cs.

Тогда в пространстве имён “MsTestRows.Rows.*”, появятся классы TestRows_01 … TestRows_100, которые содержат в себе от одного до ста генерированных методов.

Унаследуйте ваш TestClass от TestRows_NN с необходимым количеством методов (NN).

В результате, воспользовавшись таким извращенным маневром, мне удалось добиться возможности перезапустить только упавший тест.
что такое data driven тест кейс. image loader. что такое data driven тест кейс фото. что такое data driven тест кейс-image loader. картинка что такое data driven тест кейс. картинка image loader.

Исходный код и ссылки

Примечание 2: Попробуйте реализовать ConvertToNumber так, чтобы он проходил все тесты.
Внимание: придерживайтесь “авторского стиля”.

Источник

Тестирование хранилищ данных

Публикуется от имени IvanovAleksey.

что такое data driven тест кейс. f04b51cedfe54f30a75e43e382ea732f. что такое data driven тест кейс фото. что такое data driven тест кейс-f04b51cedfe54f30a75e43e382ea732f. картинка что такое data driven тест кейс. картинка f04b51cedfe54f30a75e43e382ea732f.

В интернете мало информации по тестированию Data Warehouse.
Можно найти общие требования: полнота данных, качество и т.п.
Но нигде нет описания организации процесса, и какими проверками можно покрыть эти требования.
В этой статье постараюсь рассказать: как мы тестируем Хранилище данных в «Тинькофф Банк».

Наш Data Warehouse

Сначала коротко опишу наше Хранилище.
Процессы загрузки и обработки данных реализованы в виде джобов. Джобы запускаются на планировщике обычно ночью, когда никто не использует внешние системы (нагрузка на них минимальна), и после закрытия бизнес дня.
Структура базы — это множество таблиц разного объема (от нескольких строк до 3 млрд. и более), с разным количеством колонок (от 1 до 200), с историчностью и без неё. Размер базы около 35Тб.
Используются внешние источники данных: Oracle, CSV/XLS файлы, MySql, Informix, BIN файлы, CDH – Cloudera(Hadoop). Выгружаем данные во внешние системы также через Oracle, SAS таблицы и в виде CSV/XLS файлов.
Объекты хранилища (описание баз, джобов, таблиц, вьюх и т.п.) разрабатываются в SAS Data Integration Studio и хранятся на SAS сервере в виде метаданных. Физически таблицы находятся в базах Greenplum и SAS.
Для запуска джобов, по метаданным генерируется код и переносится на деплоймент сервер. После чего они могут быть запущены на планировщике.
Изменения на среды, переносятся в виде пакетов, состоящих из метаданных и скриптов (на создание/правку физики, данных). Для удобства переноса разработчиками была написана специальная программа «Авторелиз».
Для ручного запуска джобов есть веб портал. Там же можно увидеть запущенные планировщики и статусы работающих на них джобов.

Объекты тестирования

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

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

Наш тестовый контур полностью повторяет продуктивный: тоже железо, те же данные, того же объема, загружаются и обрабатываются с помощью таких же процессов. Учитывая эту особенность, а также то, что задачи разрабатываются, когда в источниках уже есть все необходимые данные, можно без потери качества сократить объем проверок.
Нагрузочное тестирование (Performance testing) и тестирование на больших объемах данных (Volume testing) проводим только при переносе задачи на тест: проверяем время работы джоба, нагрузку на стенд(например, с помощью Grafana) и объем ворков (не буду эти проверки подробно описывать в этой статье).
На системном уровне работа джобов и качество данных проверяется автоматически. За джобами следит сам ночной планировщик и скрипт контроля объемов ворков. А данные после загрузки, проверяются с помощью Data Quality Daemon (о нем ниже). Если что-то не так с данными, ответственным приходят письма с ошибками.
Из «белого ящика» смотрим только правильное указание среды (были ошибки с хардкодом схем test и dev). В будущем планируется проверять это автоматом, при публикации пакета разработчиком.
Основными у нас являются функциональное тестирование («черный ящик») и проверка регрессии, на уровнях: компонентов и интеграции.
С учетом определенных в предыдущем абзаце объектов тестирования, полный набор проверок выглядит так:

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

Виды изменений и проверки

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

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

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

Блиц проверки

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

Если они завершились неудачно – можно сразу вернуть задачу в разработку/завести дефект Critical.

Инструменты

Основные действия во время тестирования: накат задач на тест, сравнение таблиц.
Как уже говорил, для переноса используется собственная разработка, программа «Авторелиз». Что позволяет сэкономить время и избежать ошибок при ручном переносе.

Работа программы выглядит примерно так:

Запускается через консоль. На вход подается номер задачи, имя среды и дополнительные параметры (например, делать паузу после каждого шага).

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

Количество расхождений по колонкам. Сами расхождения смотрите в difference.

Obscolumn_namediffer_base_to_comp
1column_10
2column_220
3column_30

Количество расхождений в группировках по _cd и _flg полях.

Obscolumn_namecolumn_groupbase_groupscompare_groupsdiffbase_group_pctcompare_group_pctdiff_group_pct
1column_2A1874363186800.00210.0024-0.0003
2column_2B44517401775644339840.48970.6877-0.1980
3column_2C4619311781346114980.50820.30260.2056
4column_2null19118830.00000.0073-0.0073

Для проверки качества данных используется макрос профайлинга. Который считает кол-во и процент записей с null по каждой колонке, дубли и null по ключу, строк в группировке по флагам и значениям, min/max/avg по суммам в столбцах.
На вход подается название таблицы и ключ.
На выходе получаем отчет, с табличками по каждому из расчетов.
Пример:

Количество миссингов по колонкам.

Obscolumn_namebase_nullsnulls_pct
1column_100.00
2column_200.00
3column_370.03
4column_400.00
5column_500.00

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

Контроль качества данных

Для контроля качества данных во всем хранилище используется самописный Data Quality Daemon (DQD), который проверяет все таблицы на соответствие правилам, составленными аналитиками и специалистами отдела контроля качества данных.
DQD представляет собой процесс, который каждые 10 минут находит обновившиеся таблицы и выполняет заданные SQL запросы. Результаты сравнивает с эталонными показателями (предустановленные значения) и рассылает отчет с отклонениями.
Пример отчета:

Constraint DefinitionSQL ScriptCorrupted Rows Cnt
test_schema.table1 / Unique Entity Key [id]select sum(cnt) as cnt from ( select 0 as cnt union all select 1 as cnt from test_schema.table1 group by id having count(*) > 1 union all select 1 as cnt from test_schema.table1 where not ((id ) is not null) ) sq15

Оформление тест кейсов

В нашем банке тестирование живет в Zephyr (надстройка Jira). Сами задачи на доработку оформляются как тикеты в Jira, а тест кейсы и тестраны в Zephyr.
Попробовав несколько вариантов, остановились на том, что заводим по кейсу на каждый измененный, в рамках задачи, джоб. Кейс называем: « : ». И линкуем к тикету.
Основные преимущества такого подхода:

Заключение

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *