ym104432846
Вставьте ссылку на видео из Youtube, Rutube, VK видео
Задайте вопрос по видео
Что вас интересует?
00:00:39
Понятие тестирования и автотестов:
  • Разработчики пришли к выводу, что полное тестирование всех сценариев невозможно ввиду большого количества существующих требований и сложности проектов
  • Было отмечено, что использование автотестов позволяет эффективно повторять тесты ранее выявленных сценариев без участия человека, снижая риск появления ошибок после внесения изменений
  • Участники обсуждения подчеркнули важность постоянного контроля корректности работы приложения через автоматическое тестирование, поскольку человеческий мозг ограничен в восприятии сложных взаимосвязанных структур
00:14:26
Зачем нужны автотесты и их преимущества:
  • Использование автотестов позволяет дешево тестировать старые сценарии программного обеспечения, особенно часто неизменяемые
  • Полное покрытие автотестами всех сценариев проекта обеспечивает уверенность в отсутствии скрытых ошибок после внесения изменений
  • Наличие полного покрытия автотестами повышает скорость разработки и экспериментирования над проектом, снижая страх перед большими изменениями
00:18:43
Основные виды тестов и различия между ними:
  • Обсуждались различные виды автотестов (модульные и интеграционные тесты)
  • Интеграционные тесты имитируют работу реального пользователя, взаимодействуя с приложением через интерфейс
  • Модульные тесты выполняются внутри одного приложения с тестируемым кодом, создавая специальные маленькие тестовые модули
00:21:01
Модульные тесты и их особенности:
  • Участники обсудили отличия между интеграционными и модульными тестами приложений
  • Было решено рассмотреть написание простого примера модульного теста и пошагово его усложнять
  • Объявлено, что участники будут изучать структуру модульных тестов на конкретном примере
00:23:26
Принципы написания модульных тестов:
  • 1. Обсуждаются различные подходы к тестированию программного кода (тестирование отдельных классов и функций)
  • 2. Возникло обсуждение важности покрытия тестами именно продуктовых сценариев пользователей
  • 3. Участники встречи отметили необходимость четкого понимания сущности разрабатываемого продукта перед написанием кода
00:24:43
Продуктовые сценарии и важность их тестирования:
  • 1. Для тестирования рекомендуется использовать именно продуктовые сценарии, а не внутренние компоненты приложения
  • 2. Модульные тесты следует разрабатывать таким образом, чтобы каждый тест проверял ровно один сценарий
  • 3. Каждый тест должен выдавать однозначный бинарный результат (прошел/не прошел), соответствующий проверке одного утверждения
00:27:15
Выбор тестируемой сущности:
  • 1. Обсудили вопрос выбора тестируемой сущности для проведения модульных тестов
  • 2. Определено, что тестируемая сущность может представлять собой любую часть приложения, включая отдельные страницы, попапы или даже всё приложение целиком
  • 3. Отмечено, что модульные тесты способны проверять не только небольшие модули, но и целые продуктовые сценарии
00:28:45
Результаты тестов и способы их получения:
  • 1. Тестируемая программа может иметь три типа результатов тестирования
  • Возвращаемые данные через функцию (тип 1)
  • Изменение внутреннего состояния объекта (тип 2)
  • Внешнее взаимодействие с системой (типы 1 и 3)
  • 2. Для проверки корректности работы каждого типа результата используются различные подходы и методы анализа
  • 3. В зависимости от типа результата разработчик теста выбирает соответствующий способ определения успешности выполнения продукта
00:31:18
Практическое написание простых тестов:
  • 1. Разработана структура простого приложения-тудулиста (список дел), состоящего из класса `Todolist`, команд добавления новых дел, отметки выполненных дел и очистки выполненных дел
  • 2. Созданы тесты для проверки функциональности приложения-тудулиста, включая добавление элементов, отметку дел и очистку выполненных дел
  • 3. Использован инструмент `Jest` для запуска тестов, улучшения читаемости ошибок и получения статистики прохождения тестов
00:55:06
Работа с внешними зависимостями и заглушками:
  • Рассмотрено понятие внешней зависимости в контексте тестирования программного обеспечения
  • Обсуждены методы изоляции внешних зависимостей с помощью заглушек (stubs)
  • Приведен пошаговый алгоритм добавления заглушек в тестируемый код для упрощения тестов
01:09:25
Примеры добавления точек расширения и рефакторинга:
  • Разработана концепция добавления точек расширения (API) в продуктовый код приложения, позволяющая вставлять заглушки для внешних зависимостей
  • Описаны различные способы передачи зависимостей в приложение, включая явное указание зависимостей, использование фабрик функций и классов, передачу зависимостей через замыкания и глобальные переменные
  • Рассмотрены подходы организации взаимодействия модулей в приложении с целью уменьшения количества связей между ними и упрощения управления зависимостями
01:18:45
Сложность тестирования обращений к внешним системам:
  • Для проверки корректности работы системы полива предлагается использовать специальный регистратор команд насоса, фиксирующий точное время подачи сигналов включения/выключения
  • Текущий метод тестирования влажности почвы признан недостаточно точным и длительным, поскольку изменения могут происходить в течение суток незаметно
  • Предлагается исключить проверку непосредственно состояния почвы (влажность), заменив её проверкой действий системы через регистратор команд
01:21:32
Использование специальных заглушек для тестирования:
  • Разработана новая умная заглушка (мок), способная запоминать параметры обращений и результаты тестов
  • Принято решение использовать готовое API библиотеки Jest для упрощённого создания и настройки сложных заглушек
  • Объявлен следующий пункт плана — демонстрация тестирования React-приложений
01:34:28
Использование моков и стабов в тестировании:
  • 1. Стабом — умная заглушка, автоматически подставляющая тестовые значения в код и запоминающая параметры обращений
  • 2. Заглушка помогает проверять результаты нескольких видов обращений к внешней системе в рамках одного теста
  • 3. В одном тесте рекомендуется использовать один объект-мок (мог), иначе нарушается принцип тестирования одиночного сценария
01:35:15
Организация запуска тестов:
  • 1. При написании дополнительного кода возникает сложность в понимании логики приложения и увеличивается вероятность ошибок
  • 2. Излишний код замедляет процесс сборки приложения и снижает скорость разработки
  • 3. Код, предназначенный исключительно для тестирования, полезен благодаря автоматизации проверок и снижению ручной работы
01:37:02
Создание нескольких файлов тестов и их последовательный запуск:
  • 1. Участники обсудили возможность запуска тестов из нескольких отдельных файлов, используя параметризированный список файлов в документации джеста
  • 2. Предложено использовать правило именования файлов (например, добавлять суффикс "_test_jes") для упрощения поиска подходящих файлов
  • 3. Для автоматизации запуска тестов предложено применять маску поиска файлов внутри проекта, задаваемую через параметры джеста
01:38:00
Настройка запуска автотестов на этапах пуша и пулреквеста:
  • 1. В проекте настроен автоматический скрипт запуска автотестов при создании пуллреквеста и перед релизом продукта
  • 2. Автотесты необходимы для проверки корректности изменений разработчика и совместимости нескольких пуллреквестов в основной ветке
  • 3. Возможность отказа от настройки автотестов допускается в случае срочной разработки программного обеспечения, предназначенного для одноразового использования
01:39:31
Методология разработки, управляемая тестами:
  • 1. Обсуждалась методология разработки программного обеспечения «тест-драйв девелопмент», предполагающая написание тестов перед реализацией кода приложения
  • 2. Участники отметили удобство данной методики для написания тестов, облегчающих структурирование требований и понимание предметной области
  • 3. Один из спикеров сообщил, что сам лично данную методику ранее не применял
01:41:46
Реализация тестов для React-приложений:
  • 1. Разработано небольшое приложение-тудулист на реакте с пользовательским интерфейсом и возможностью сохранения состояния между страницами
  • 2. Для работы приложения используются библиотеки React (для переключения урлов) и Redux (для хранения состояния)
  • 3. Участники встречи выразили готовность разбираться в представленной разработке и уточнили возможность задать уточняющие вопросы в комментариях к трансляции
01:43:18
Модульное тестирование React-компонентов:
  • Проект создан через создание приложения на основе шаблона Create React App
  • Для упрощения разработки выбрано считать всё приложение одним модулем
  • Настроено использование тестов (Jest), созданы начальные файлы тестов и описаны шаги по написанию первого простого теста
01:49:24
Работа с DOM-элементами в тестах:
  • Разработана заглушка для эмуляции API браузера, использующая библиотеку doms.js (дом JavaScript)
  • Библиотека Testing Library содержит вспомогательные функции для рендеринга приложений, созданных на разных фреймворках, включая React
  • Создан специальный атрибут `data-test-id` для идентификации элементов интерфейса и упрощения взаимодействия с ними во время тестирования
01:56:01
Изоляция тестов от внешних зависимостей:
  • Разработана методика тестирования веб-приложений с использованием памяти компьютера (плейграунда)
  • Создан механизм проверки корректной работы приложения без участия человека
  • Применена библиотека React Test Library для поиска и взаимодействия с DOM-элементами
02:00:37
Тестирование роутинга в React-приложениях:
  • Для тестирования перехода между страницами (роутинга) используется библиотека `react-router-dom` и создается заглушка `memory history`
  • Для проверки правильности перехода по ссылкам применяется метод клика по элементу с атрибутом `data-test-id`, отслеживается изменение состояния приложения
  • Вопрос о возможности появления атрибута `data-test-id` в продакшен-бандле решается путем добавления/удаления атрибута на этапе сборки проекта с использованием плагинов Webpack
02:17:50
Особенности написания тестов:
  • 1. Обсуждались характеристики полезных тестов (надежность указана как одна из характеристик)
  • 2. Речь шла о необходимости написания тестов, полезных для проекта
  • 3. Участники вернулись к обсуждению презентации тестов после первоначальных замечаний
02:18:17
Надёжность тестов:
  • Для повышения доверия к тестам рекомендуется регулярно актуализировать список тестовых сценариев и обеспечивать покрытие тестами важных функциональных сценариев приложения
  • Код покрытия (code coverage) показывает, насколько часто различные участки кода выполняются во время тестов, однако сам по себе высокий процент покрытия не гарантирует надежность тестирования
  • Рекомендуется избегать добавления сложной логики в тесты, разделять тесты на отдельные части, проверять работоспособность тестов при наличии ошибок в коде и изолировать тесты от внешних зависимостей и друг от друга
02:28:09
Легкость сопровождения тестов:
  • Участники обсудили важность тестирования интерфейса, а не деталей реализации программного продукта
  • Предложено избегать дублирования проверок в тестах одного сценария, выделяя общие части тестов в отдельный хелпер
  • Рекомендуется применять гибкие методы проверки результатов (например, использование функции `contains`), чтобы избежать ложных срабатываний тестов при изменениях внутренней логики программы
02:33:46
Понятность тестов:
  • Рекомендации по названию тестов
  • Название тестов должно быть осмысленным и содержать информацию о контексте тестирования, сценарии и ожидаемом результате (например, «Кликнул корзину → блок удалён»)
  • Использование API и кастомных проверок
  • Рекомендуется использовать подходящие API для проверок, чтобы получить дополнительную информацию о результатах тестов прямо в отчёте
  • Можно создавать кастомные проверки, расширяя возможности API, что улучшает читаемость тестов
  • Вынесение рутинного кода в хелперы
  • Необходимо выносить вспомогательные функции и рутинный код в отдельные хелперы, чтобы оставить в тестах только важную логику, повышая читаемость и удобство сопровождения тестов
0: Всем привет, меня зовут Дима. Мы будем сегодня говорить про автотесты. Я знаю, что нас сегодня смотрят студенты шри, слушатели открытого лектория и слушатели.
1: Из яндекса наша лекция займёт в районе 2 часов. И если у вас возникнут походу вопросы, то в описании должна быть ссылка на специальный сервис, в котором их можно задавать. Я буду периодически прерываться, смотреть туда и
2: И те вопросы, которых больше всего лайков. Ну, буду на них отвечать. Поэтому, в общем, не стесняйтесь туда писать и лайкать другие вопросы, которые покажутся интересными. Мы будем сегодня говорить про автотесты в целом.
3: Что это такое, как они помогают разработчику решать его задачи, приносят какую-то пользу при разработке интерфейсов. И мы поговорим сегодня о таком виде тестирования, который называется модульной.
4: Тестирование или юнит тестирование. Ну, юнит по-английски модуль. Собственно, давайте начинать. Прежде чем говорить про автотесты, надо определиться сначала, что значит вообще
5: В принципе, слово тестирование, я, наверное, не скажу вам ничего неожиданного, если скажу, что тестирование это проверка того, что ваш код работает правильно? Казалось бы, это очень такое очевидное определение. Но тут есть 1
6: Момент, что значит работает правильно, правильно. Это значит, что к вашему коду есть какие-то требования, то есть вы разрабатываете ваше приложение и к вам кто-то пришёл и сказал, каким оно должен должно быть.
7: Требования. Неважно, в каком виде они существуют. Они могут быть написаны в виде технического задания, могут быть описаны в каких-то тикетах, в трекере могут быть просто в блокноте у вашего менеджера или у кого-то в голове, или
8: Ну, любым способом описаны требования. Главное, что они есть. И в этих требованиях обязательно описаны какие-то продуктовые сценарии. То есть, что можно делать с вашим продуктом и описаны результаты, которые ожидаются на
9: Выходе. И вот правильно это значит, что если вот вы написали какой-то продукт, если с вашим продуктом сделать действия, описанные в продуктовых сценариях, в требованиях, то тогда на выходе будут Ровно такие результаты, как ожидается,
10: То есть вообще понятие правильно зависит от той задачи, которую решает ваш продукт. Что же такое автотесты? Автотесты это маленькие программы, которые вот как вот эти роботы тестировщики тестируют.
11: Вашу большую программу, ваш продукт, который вы пишите, как они это делают. У вашего продукта есть наверняка какой-то интерфейс. Это может быть программный интерфейс, может быть пользовательский интерфейс, например, всякие кнопочки, на которые можно тыкать в браузере.
12: Автотесты делают при помощи этого интерфейса над вашим продуктом какие-то действия, описанные в продуктовых сценариях, и потом проверяют результат, ну, который получился на выходе. Соответствует ли он ожиданиям в этом ключевое
13: Отличие автотестов от тестировщиков. Тестировщик, ну, от ручных тестировщиков, от людей. Люди придумывают эти сценарии и ищут, чтобы такого ещё проверить, чтобы найти там, где в вашем продук.
14: Bug. Ну, надо его найти, соответственно, и исправить автотесты ничего не придумывают. Они тупо как бы делают те действия, которые запрограммировал. Вот автор автотестов и суть автотестов не в том, чтобы найти новый сценарий.
15: В том, что вы можете вот найденные уже сценарии, которые вы когда-то придумали, вы можете их запрограммировать и потом перетестировать их повторно очень дёшево, без человеческого участия. У вас, наверное, возникает следующий вопрос.
16: А зачем тестировать одно и то же повторно? Ну, если и так известно, что оно работает. И тут как бы короткий ответ в том, что сложность продуктов, которые вы разрабатываете, очень большая она.
17: Выше, чем лимит восприятия человеческим мозгом. И ни 1 человек не может держать в голове подробно, как работает ваше приложение, поэтому вам нужно
18: Постоянно проверять, что там ничего не сломалось. Вот давайте проведём небольшой эксперимент. Попробую я сейчас буду показывать жёлтые кружочки, а вы попробуйте вслух называть их количество как можно быстрее. Если кто-то смотрел лекцию предыдущего года, то он
19: Уже знает, чем закончится. Ну, кто не смотрел, прям попробуйте это сделать вживую. Вот сколько кружочков? Очевидно, что 3, да. А сейчас сколько кружочков? Ну, тоже легко посчитать, это 5. Вот. А сейчас
20: Сколько кружочков? Тут вы должны почувствовать разницу. Вот как вы воспринимали 5 кружочков и как вы воспринимаете 11 кружочков? Их тут 11 должно быть, разница есть.
21: Из за того, что у человеческого мозга есть лимит на количество сущностей, которые он может одновременно обрабатывать, это в среднем там 7 сущностей. Ну у разных людей, там плюс - 2. И вот если количество
22: Сущности, с которыми вы работаете меньше 7, то тогда вы видите их, ну, каждую по отдельности можете вот замечать, как бы, что происходит в каждой отдельной сущности. Если количество сущностей, допустим, 9, то вы восприни
23: Понимаете их уже как 1 большую кучу и вы не видите, что происходит с каждой из них. Вот сколько тут кружочков. В общем, много. Вы наверняка видите это как 1 большую кучу. Вот. А теперь
24: Представьте себе, что вот эти кружочки это модули вашего проекта, то есть вы пишите какое-то большое приложение, это его модули, между ними существуют какие-то связи обратите внимание, тут вот 18 кружочков и вам уже тяжело держать это в голове. А в rare
25: Проектах их могут быть там сотни или 1000. И к чему это, говорю, ни 1 человек, какой бы крутой разработчик он ни был, не может держать в голове весь код проекта, над которым он работает. Ну, современ.
26: Проекты очень большие. Вот. И теперь представьте, что у вас есть вот такой проект. Вам нужно внести туда изменения, а вы не можете держать в, ну вы вообще не понимаете, что там происходит. Ну даже если вы в каком-то 1 кружочке разберётесь начне,
27: Разбираться в следующем. Вы предыдущий как бы быстро забудете. Вот, ну и как в таком случае происходит работа над проектом. Как правило, вот вам пришла задача, вы сначала начинаете смотреть там список файлов
28: Проекта там вбивать что-нибудь в поисковую строку в вашем редакторе кода и искать хотя бы приблизительно то место, которое похоже на нужное допустим вот вы нашли вот этот красный кружочек
29: Дальше вы начинаете погружаться в то, что там написано, начинаете читать этот код, запускать, смотреть в отладчике, какие там данные приходят. То есть вы загружаете это как бы себе в оперативную память, что, что происходит в остальных кружочках, вы не знаете, вы
30: Именно погружаетесь вот в конкретное место, которое вам надо поменять. Допустим, это место зависит от каких-то других мест. И вам тоже нужно понимать, как они работают для того, чтобы решить вашу задачу. Что вы делаете? Вы обнаруживаете эту зависимость?
31: Идёте вот в эти соседние модули и начинаете изучать их тоже дальше, когда вы как бы загрузили все это себе в голову в вашу оперативную память, вы начинаете вносить изменения, запускать это и как-то тестировать, отлаживать.
32: И смотрите, что получается вот вы поменяли какие-то модули, но от ваших изменений может зависеть очень много всего. И там вплоть до того, что там весь проект может поломаться, но
33: Вы не погружались в код вот этих вот Синих, ну, модулей, которые я отметил синим цветом. И на самом деле вы даже не всегда можете сходу сказать, на какие модули повлияли ваши изменения. То есть вот вы что-то меняете, вы могли
34: Что-то сломать. И проекты настолько большие, что у вас нет способа узнать об этом, ну узнать о том, что у вас что-то сломалось. Вот. И что же в этом случае можно сделать? Во первых, ну типа самый
35: Такой 1 вариант, который приходит в голову, это надо все перетестировать. Вот вы работаете над проектом, сделали там какую-то, ну запилили какую-то новую фичу, потом отдаёте это тестировщику, и он начинает перетестировать, но он перетестируй. Понятно?
36: Не новую фичу, ну не только вашу новую фичу, а он перетестируй весь проект, потому что могло сломаться что угодно. И вы не знаете, где что могло сломаться. Тут есть 1 нюанс. Вот эти старые сце.
37: Сценарии, которые нужно перетестировать, будут постоянно, ну и их будет постоянно очень большое количество. Вот я на диаграмме обозначил фиолетовым цветом старые сценарии, которые были в проекте до того, как вы начали добавлять
38: Да, новую функциональность и зелёным цветом обозначил количество сценариев, которые появились вот в ходе вашей работы. И теперь смотрите, когда вы делаете следующую фичу, то те сценарии, которые были новыми
39: Для предыдущей фичи, для следующей они будут уже старыми. И это значит, что с каждой фичей у вас количество старых сценариев будет расти. И это значит, что вы очень быстро придёте в такое состояние, когда
40: У вас количество старых сценариев, которые нужно перетестировать, будет сильно больше, чем количество новых. То есть вы при желании можете поддерживать вот это количество новых сценариев маленьких, маленьким, если будете дробить Зада.
41: На маленькие кусочки и каждый раз делать по чуть чуть, но количество старых сценариев у вас будет гарантированно, всегда будет многократно больше. И вы придёте просто к ситуации, когда вы, допустим, запилили новую фичу,
42: Отдали это тестировщику, он такой там за день протестировал ваши новые сценарии, которые появились. А потом он такой запирается в комнате на 3 месяца, там заказывает много пиццы и начинает по очереди вот эти все, все, что было сделано там.
43: Начало проекта до текущего момента он начинает все это перетестировать. Ну, понятно, что при такой ситуации разработка, ну, вообще любые изменения в проекте будут очень дорогими, и это неприемлемо. Вот. Что же ещё можно?
44: Сделать, если не получается все перетестировать, можно принять волевое решение, что и так сойдёт и катить это в prod без тестирования как вот этот парень в общем вы наверное смеётесь над картинкой, но
45: На самом деле, как, ну, как говорят, смешная ситуация, страшная. Ну, многие реально так делают. Вот на моей предыдущей работе мы так и делали, потому что, ну, нет, у нас было какое-то тестирование, оно перед, ну, тестировало руками.
46: Какие-то критичные сценарии перед релизом, но понятно, что там на 3 месяца мы не могли себе позволить как бы отдать это в тестирование, чтобы проверить прям все все все все и поэтому катили просто в prod.
47: Так как есть ну да, иногда в prod выкатывались какие-то баги, но с другой стороны, баги по идее должны быть редкими, потому что мы же меняли вот какой-то конкретный кусок, мы его протестировали, все остальные куски мы вроде не меняли, ну.
48: Да, там могут быть зависимости, вот эти вот синие кружочки, которые я рисовал. Вот. Но, наверное, они будут не каждый раз. И, ну, каждый раз можно это не перетестировать. В общем, это реальный как бы, подход, который много где.
49: Пользуется. Это очень печально, потому что баги попадают, ну, от того, что вы приняли такое решение. У вас баги, если они есть, они не исчезли, и они попадают вашим пользователям. Ваши пользователи встречаются с каким-то некорректным поведением.
50: В результате ваша компания теряет деньги. Я сделал небольшой слайд с расчётами. Представьте себе, что у вас есть баг, при проявлении которого 1 раз у 1 пользователя компания теряет 10 ₽. Что это значит? Значит, если у вас
51: Посещаемость 100000 человек в месяц. Ну вот 100000 человек, у них 100000 раз произошёл этот баг. Это значит, что ваша компания за месяц тупо потеряла 1 000 000 ₽. А теперь можете ещё дальше представить. Представьте, что вы работаете в common
52: Которая пилит страницу поисковой выдачи яндекса. У вас там 150000000 человек в месяц. Значит, что вот ваша компания потеряла полтора миллиарда рублей на вот этом вот маленьком баге, то есть потери от бага.
53: Умножаем на количество пользователей. И вот когда мы думаем об 1 пользователе, кажется, что это мелочь. Но если вы, ну вот 100000, вот этот вариант, который на 2 строчке, это не такой уж и большой сайт, это средних размеров интернет-магазин, вот, и
54: И вы уже там, на таком маленьком баге теряете 1 000 000 ₽. В общем, это, ну, к этому надо подходить серьёзно, и надо всеми силами стремиться, чтобы багов не было. И, значит, катить в прод без тестирования. Это не наш вариант.
55: Соответственно, мы поняли, что все перетестировать мы не можем, катить без тестирования тоже не можем. Ну, вы догадываетесь, какой тут способ, как, что с этим можно сделать.
56: Можно писать автотесты. Мы сейчас перед этим говорили с вами, что автотесты позволяют дёшево перетестировать старый код. Это как раз вот Ровно то, что нам нужно. У нас огромное количество старых сценариев, они редко меня их 1 раз запрограммировали, и они редко меняются, и нам надо
57: При каждом внесении изменений их перетестировать. Вот автотесты отлично подходят для этого. Но тут тоже есть 1 нюанс. Автотесты должны давать гарантию. В общем, представьте себе, что у вас есть телепорт.
58: Ну, который ещё не изобрели, но представьте, что изобрели. Очень крутая штука. Может мгновенно доставить свой груз там, в другую точку земли, например, не знаю, в Австралию из Москвы. И представьте себе, что ваш телепорт работает.
59: Корректно, в 80 процентах случаев, а в 20 процентах случаев он уничтожает свой груз. Вопрос, будете ли вы им пользоваться? Ну, очевидно, нет, потому что кажется, что вероятность 20% небольшая, но вы можете заплатить за это.
60: Очень большую цену, то есть умереть и вероятность 20%, что вы умрёте, это как бы серьёзный риск. Скорее всего, вы туда не будете даже домашних животных отправлять. Ну но при этом телепорт остаётся офигенным девайсом. Вы можете
61: Туда, допустим, вот бутылку воды положили, и она мгновенно оказалась в Австралии. Она бы могла туда лететь, там 2 недели на самолёте или плыть 2 месяца на корабле, а она попала туда мгновенно. Ну да, она может не долететь, но, ну, это
62: Даже бутылка воды не долетела. Ладно, вы положили туда ещё 1, и вот 2 уже с большой вероятностью долетит. То есть телепорт приносит пользу. Это офигенная крутая штука, но сами вы им пользоваться не можете, потому что он не даёт вам гарантию автотесты.
63: Это вот с автотестами. Ситуация очень похожа. Представьте себе, что у вас есть проект, который на 80% покрыт автотестами, и он очень дёшево позволяет автоматически проверить многие сценарии, но
64: 20% сценариев не покрыты автотестами, и вы не знаете, вот по каким местам проекта они рассредоточены. Вопрос, можете ли вы вот релизиться и доверять? Ну, быть уверенны, что у вас нет багов отказаться от тестирования.
65: Релиза. Ну, очевидно, нет, потому что вы не знаете, где у вас могут произойти проблемы и насколько серьёзные проблемы у вас могут произойти. Поэтому автотесты это, конечно, круто, если у вас будет баг в тех сценариях, которых
66: Которые ими покрыты, то они помогут вам его обнаружить, но по хорошему вам все равно надо все перетестировать. Вот к чему я это говорю. Есть очень большая разница между просто какими-то, ну,
67: Каким-то небольшим количеством автотестов или даже там средним количеством. И ситуация, когда у вас покрыт автотестами весь проект, когда у вас покрыто автотестами, все, ваш проект приобретает дополнительное качество, это гарантия
68: Что ваши изменения ничего незаметно не сломают. И вот это качество даёт вам очень много. Оно даёт вам смелость при принятии проектных решений. То есть, если у вас нет автотестов, то вы
69: Вносите изменения очень осторожно, очень аккуратно. Вы боитесь вносить большие изменения, и ваш проект развивается медленно. Если у вас все покрыто автотестами, то вы можете делать какие-то эксперименты. И если вы что-то сломаете автотест,
70: Сразу вам это покажут. В общем, это супер крутое качество, которое сильно влияет на то, как идёт разработка проекта. Вот, и автотесты это, ну, в больших проектах автотесты.
71: Это не просто какой-то инструмент, который помогает находить баги, это необходимый инструмент, без которого развитие большого проекта просто невозможно.
72: Автотесты должны давать гарантию. Надеюсь, я сейчас вас убедил, что автотесты это необходимая вещь на больших проектах. И, надеюсь, вы теперь понимаете, почему это важно, какую конкретно пользу они приносят.
73: Смотрите, дальше мы будем говорить про, ну, мы будем говорить про 1 из видов тестирования. Это модульные тесты. Автотесты можно разделить.
74: По признакам, которыми они обладают на разные категории. Ну то есть есть много разных подходов, много разных инструментов. Вы пишите, ну вот эти все инструменты и подходы, их суть сводится к тому, что вы пишите какую-то маленькую программу, котора
75: Тестирует вашу большую программу. Вот. И в зависимости от того, какими признаками обладают эти подходы, их там группируют. Ну, в какие-то группы этих группировок может быть много, но вот я буду рассказывать про, ну, мне кажется, это основная группировк
76: Самая такая известная, самая популярная. Модульные тесты и интеграционные тесты, интеграционные тесты это тесты, которые, в которых тестовый код, вот этот код, который проверяет ваши сценарии, запус.
77: Ну, в отдельном приложении, не в том же самом, которое вы разрабатываете. Поэтому для тестового кода ваше тестируемое приложение выглядит как такой чёрный ящик. То есть у вашего приложения есть какой-то интерфейс и ваш тестовый код.
78: Вот общается с этим черным ящиком через интерфейс. Вот этот чёрный ящик, как правило, является, ну, всем вашим приложением в сборе вместе там с фронтендом бэкэндом, там может быть база данных.
79: Чем это вот очень похоже на то, как реальный, ну как настоящий живой тестировщик проверяет ваше приложение, то есть он открывает это в браузере, видит там какие-то кнопочки, вводит туда данные, ну, в соответствии с тестовыми сценариями, вот, и смотрит, что
80: Вывелось на экран. Модульные тесты могут запускаться внутри 1 программы с тестируемым кодом. То есть, когда вы запускаете модульный тест, у вас может запускаться не настоящее продуктовое приложение, а
81: Какое-то специальное маленькое тестовое приложение, которое внутри себя создаёт экземпляры тестируемых модулей, то есть модуль, ну за счёт того, что модульные тесты работают внутри 1 приложения с вашим продуктовым кодом, они могут
82: Создавать как бы отдельные части вашего приложения и могут взаимодействовать с ним таким образом, которое недоступно интеграционным тестам, например. Ну ладно, мы об этом поговорим позже. В общем, вам сейчас главное запомнить. Вот
83: Это отличие, что интеграционные тесты проверяют ваше приложение как чёрный ящик. Они как бы находятся сбоку и не знают, что внутри приложения модульные тесты находятся внутри 1, грубо говоря, процесса операционной системы. Ну, как вариант.
84: И они знают, из каких частей состоит ваше приложение. Могут тестировать их по отдельности. Вот дальше мы будем говорить про модульные тесты. У меня есть ещё 1 слайд, он, я каждый год рассказываю эту лекцию. Это 1 из важных слайдов.
85: В общем, все, что я вам расскажу, это не какие-то правила, которые, которые нужно слепо выполнять, а это информация, которую вам нужно учитывать при принятии своих решений. Но важно, чтобы ваши решения, которые вы принимаете.
86: Были сделаны на основе логики и здравого смысла. То есть вот вы сейчас из лекции узнаете там, что на что влияет там, как что устроено, какие есть варианты, но всегда принимайте решения на основе здравого смысла, если вам нужно
87: Там поставить какой-то страшный костыль. Вот конкретно в вашей ситуации он лучше решает вашу задачу, чем следование этим правилам, то ставьте костыль, просто понимайте, какую цену вы заплатите и какую пользу получите. Всегда старайтесь получить максимальную пользу, а не ту.
88: Выполнить рекомендации.
89: Так, про вопросы. В общем, наверное, сейчас не будем останавливаться на вопросы, а после следующего раздела
90: Смотрите, мы сейчас попробуем написать простой модульный тест. Мы сделаем такой как бы примитивный совсем пример, а потом будем его постепенно усложнять. И, ну, на этом примере будем разбирать
91: Какие-то основные идеи, как писать модульные тесты собственно вот в 1 примере мы постараемся разобрать из чего, ну там какова структура модульных Тестов, то есть из какой из каких частей он состоит и ну типа
92: Как это все работает? Вот прежде чем писать код, мы отметим, ответим на 3 вопроса. Нам эти ответы супер важны для того, чтобы понять, что писать внутри. 1 вопрос это что мы будем?
93: Тестировать. Есть разные как бы мнения, ну типа, что нужно тестировать. Например, есть мнение, что вот ваша программа, она в принципе состоит из каких-то классов, функций. И если вы
94: Ну там, не знаю, react, компонент это по сути тоже либо класс, либо функция. Ну, если мы говорим про интерфейсы или там компоненты каких-то любых других фреймворков, ну тупо, потому что джаваскрипт как бы предлагает вам такие абстракции. Класс, функция, вот.
95: И есть мнение, что надо тестировать там каждый класс, каждую функцию. То есть если вы описываете какую-то сущность в коде, надо написать на неё тесты. В общем, к чему это может привести. Это может привести к тому, что
96: Вы, ну, покрыли тестами классы и функции, но ваше же приложение решает какую-то задачу пользователя. Вот эти вот продуктовые сценарии, про которые мы говорили в самом начале, и может оказаться, что вот вы
97: Покрыли отдельные части вашего приложения внутренности, а продуктовый сценарий на самом деле работает некорректно. Вот. Поэтому вот сразу запомните, что тестировать вообще любыми автотестами нужно именно продуктовые сценарии, не
98: Какие-то там кишки вашего приложения, а то, что реально важно для пользователя, тестируйте продуктовые сценарии. Теперь следующий момент, когда вы пишите модульные тесты, то старайтесь писать
99: Их так, чтобы каждый тест проверял Ровно 1 сценарий. То есть когда пользователь делает какие-то действия с вашим приложением, например, он заполняет какую-то регистрационную форму, там происходит много действий, то есть он вводит там фамилию, имя.
100: Оно производит валидацию, там, ну, например, он вводит логин, под которым хочет зарегистрироваться. Вы ходите на сервер, проверяете, что такого пользователя ещё нет. Потом он там вводит свой возраст, там ещё какие-то действия, он поставил галочку, у него разблокировалось, типа
101: Формы, который нужно дополнительно заполнить. Вот когда вы запускаете тест, который что-то проверяет, тест, вам выдаёт бинарный результат, либо да, либо нет. И у вас много действий. И если вы хотите знать пра,
102: Ли, они работают. Вам нужно по каждому действию получить такой результат. То есть, что валидация, допустим, Логина работает, правильно, что вот эта галочка, которая открывает дополнительную часть формы, ну, работает правильно? Правильно? Это так, как описано.
103: В требованиях. И вот вам нужно получить много вот этих бинарных результатов, да или нет. Поэтому вот каждое утверждение, на которое вы можете ответить, да или нет, это отдельный сценарий. И когда вы пишите модульные тесты, вам нужно
104: Ну, вам будет намного проще с ними работать, если вы напишите на каждый сценарий отдельный тест. То есть в сценарии могут происходить много действий, но в каждом сценарии должна быть проверка, которая проверяет
105: 1 конкретное утверждение. Опять же, это может быть не 1 проверка, это может быть какая-то комбинированная проверка, но важно, что 1 проверка, говори, ну, даёт вам 1 тест, даёт вам Ровно 1 результат. Либо он упал, либо он прошёл. Вот
106: Вот это супер важный принцип. Пожалуйста, запомните его дальше. Вот мы ответили на вопрос, что мы будем тестировать. То есть это какой-то продуктовый сценарий и мы пишем по 1 тесту на каждый сценарий. Дальше смотрите.
107: Нам нужно внутри теста создать экземпляр вашей тестируемой сущности и делать над ним какие-то действия. Нужно понять, что будет являться вашей тестируемой сущностью. Есть опять же распространённое мнение, что модульные тесты
108: Проверяют только какие-то маленькие модули вашего приложения и, допустим, функция, не знаю, функция форматирования даты это вот ваш модуль, а допустим, страница приложения это не модуль, потому что у неё внутри много всего другого.
109: На самом деле, ну тут опять смотрите, какую вы пользу получаете от того, что тестируете только маленькие сущности. Ну, обычно ваши продуктовые сценарии содержат, ну, в них задействовано какое-то большое
110: Количество сущностей. И, ну вам интересно покрыть именно большие сущности. Те, которые содержат логику сценария целиком. В общем, к чему это говорю, тестируемые сущности.
111: Вот этим модулем может являться любой кусок приложения. Это может быть, допустим, какой-то попап, который у вас в интерфейсе возникает, или целая страница, или вообще все приложение. Если ваша логика распределена по всему приложению, то вашей тестируемой сущностью может быть и все прило.
112: И, ну, в общем, не думайте, пожалуйста, что модульные тесты проверяют только что-то маленькое. Тестируемая сущность это то, что целиком содержит ваш продуктовый сценарий.
113: Смотрите, мы ответили на 2 вопроса, что, что тестировать и экземпляр какой сущности нам нужно создать в тесте? 3 вопрос. Что мы будем считать результатом выполнения нашего продуктового сценария? И тут все просто на самом деле у вас
114: Всего 3 варианта, что может быть результатом. 1 вариант это когда ваша тестируемая сущность что-то возвращает из какой-то функции через ключевое слово return. Это вот данные, которые явно как бы выходят наружу.
115: Из вашей сущности. То есть вы выполнили какие-то, вы создали экземпляр вашей сущности, выполнили над ней какие-то действия, она явно вам выдала на выход какие-то данные, и вы посмотрели, ну написали условия по этим данным и определили, прошёл тест или упал, в общем,
116: Это 1 тип результата. Результат, который возвращает функция. 2 тип результата это изменение внутреннего состояния объекта. Вот вы можете видеть на слайде, тут написан класс, он называется my input. Но это похоже на какое-то поле ввода.
117: И у него вот есть метод сет велью, то есть вы перед, ну, судя по названию, это какая-то команда, которая меняет текст в вашем поле ввода, вы туда передаёте какое-то значение, и он сохраняет это во внутреннее поле, вот сет велью наружу.
118: Ничего не возвращает, но при этом он выполняет полезную работу. Он меняет внутреннее состояние вашей системы, вашего импута. И для того, чтобы вам проверить, что он корректно отработал, что состояние изменено. Правильно? Вам нужно посмотреть.
119: На вот это внутреннее поле велью. То есть это 2 тип результата. 1 тип результата, когда информация явно выходит из вашей тестируемой сущности через return. 2 тип результата, когда меняется внутреннее состояние, и вы смотрите на него и таким образом определяете правильно прошёл
120: Или нет. Вот и 3 тип результата это обращение к внешней системе. Вот тут тоже есть метод синг, он не возвращает никакие данные, он не меняет никак внутреннее состояние системы, он что-то там отправляе.
121: На сервер, вот через команду Феч обращение к внешней системе это тоже результат. То есть, если вы хотите проверить, что ваша синхронизация правильно отработала, то вам нужно проверить, что
122: Обращение к внешней системе действительно было и что оно было с правильными параметрами. Вот, вот такие 3 результата могут быть у вашей программы, которую вы тестируете. И, ну то есть вы, когда пишите тест, всегда это будет 1 из этих 3 вариантов для того, чтобы написать
123: Тест. Вам нужно понять, с каким вариантом вы работаете. И теперь, когда мы разобрали эти 3 вопроса, давайте попробуем переключиться в редактор кода и, ну
124: В соответствии вот с этими, с этой информацией написать тест.
125: Так, у меня открыт сейчас редактор это вскод, вы видите тут пустую папку, тут есть вот json и никаких файлов, давайте сделаем небольшое приложение, которое мы будем тестировать.
126: Это будет тудулист, потому что эту предметную область все знают. Это, ну, список дел, в котором можно их отмечать галочками.
127: Я заготовил небольшие сниппеты, чтобы быстро набирать текст. В общем, это класс, туду, лист, он в конструкторе принимает список строк, но это называ.
128: Ваших дел, с которыми вы будете работать. У него есть команды добавить новое дело в список. Есть команда отметить дело как выполненное. Вы передаёте индекс, ну, номер элемента списка, вот и есть.
129: Команда clear, которая удаляет выполненные дела из списка. Вот также смотрите, тут используется ещё 1 вспомогательный класс. Тудайти. Давайте я тоже его добавлю.
130: Этот, ну тут, наверное, нечего разбирать, это просто элемент списка, у которого есть name. И признак того, что он выполнен и есть команда дан, которая ставит эту галочку в true. Вот также я экспортировал
131: Эти сущности наружу, чтобы можно было обращаться к ним из других файлов. Теперь я делаю 2 файлик, называем его тест джес и будем в нём писать наши тесты.
132: Я добавил сюда 1 тест это просто функция. То есть мы говорили, что автотесты это программа, которая маленькая программа, которая тестирует вашу большую программу по каким-то сценариям, что тут происходит. Тут есть 3 части.
133: Эти 3 части соответствуют вопросам, о которых мы сейчас с вами говорили. 1 часть это подготовка, то есть она создаёт какой-то контекст, в котором будет происходить наш тестируемый сценарий. В частности, она создаёт наш
134: Вот эту тестируемую сущность, ну вот новый экземпляр тудулист и передаёт ему какие-то начальные айтимы. 2 часть это действие. То есть вот это отвечает на вопрос, какую сущность мы тестируем вот эта часть
135: Для того, чтобы её написать, нужно ответить на вопрос, какой сценарий мы тестируем. Я, ну, не буду на этом останавливаться. Просто для примера мы взяли сценарий, который проверяет добавление элемента. Вот. И 3 часть это проверка, это
136: Часть, которая проверяет результат нашего сценария. Смотрите, тудулист, ну, когда мы добавляем элемент какой у него будет тип результата, ну, это будет изменение внутреннего состояния системы. То есть он в какое-то своё поле положил дополнитель.
137: Элемент, поэтому мы в проверке смотрим на внутреннее состояние нашей системы. Наш лист, у него есть поле айтинс, и мы проверяем вот функция, сам это функция массива, которая возвращает true, если для
138: 1 хотя бы для 1 из элементов выполнено вот это условие. То есть у нас был 1 элемент, мы добавили туда элемент со словом тест. Дальше. Если вот это условие выполнено, то мы ничего не делаем. Если оно не выполнено. Восклицательный знак.
139: Начале, то мы зайдём внутрь этого ифа и сгенерируем исключения. То есть для того, чтобы писать тесты, в принципе не обязательно использовать какие-то специальные инструменты. Вот наша программа, которую мы сейчас написали, она
140: Выполняет вот это тестирование и приносит, в принципе, пользу. Давайте попробуем запустить. У нас это обычный javascript file, мы запускаем его через not jazz.
141: Вот он выполнился, не упал. Давайте, давайте я напишу сюда сразу ещё 1 тест.
142: Вот написал тест, который проверяет, что можно отмечать элементы галочкой по индексу. Давайте опять напишем, запустим. Это ничего не упало. Теперь смотрите, мы идём
143: В наш файлик и пробуем сломать наш тест.
144: Вот я закомментировал в команде эд айтим тот код, который добавляет новый элемент.
145: Запускаем. Опять ничего не упало. В общем, кто смотрел предыдущую лекцию, знает, в чем тут подвох. В общем, смотрите, мы в нашем тесте описали, ну, описали 2 теста, но никак их не вызвали. Вот на
146: Надо их вызвать. То есть вы поняли, да, что произошло? Мы написали тесты, но когда мы запускали этот файлик, они по факту не выполнялись. Вот на самом деле, тут, кроме того, что надо их вызвать, надо ещё добавить.
147: Импорты, то есть мы обращаемся к туду листу, но никак его не импортировали.
148: Вот. Теперь, если мы запустим наши тесты, то у нас должно все упасть, да, вот у нас свалился туду, ну, в общем, свалился тест, который проверяет добавление элемента, потому что, ну,
149: Мы закомментировали строку, которая делает вот это ключевое действие. Вот к чему я вам это все показываю. Очень важно проверять, что ваши тесты корректно работают, а корректная работа теста это отлавливать ошибки. То есть вы, когда вы
150: Писали тест, обязательно пойдите сделайте ошибку в вашем коде и проверьте, что тест корректно её отловил. Вот мы потом про это ещё отдельно поговорим про ошибки в тестах. Ну, в конце лекции. Вот давайте я
151: Верну это обратно. Давайте проверим, что наши тесты начали запускаться во теперь смотрите, круто мы починили тесты, что тут можно улучшить, во первых.
152: Смотрите, мы сейчас запустили с вами тесты, они что-то сделали и ничего нам не написали, и мы даже не знаем, выполнились они или нет. Во вторых, когда мы вот по очереди, мы написали 2 теста, мы запускаем их по очереди.
153: Допустим, 1 тест упал, он выкинул исключение. Выполнение программы остановилось и до 2, до выполнения 2 теста у нас дело не дошло. Тоже не очень хорошо. То есть у нас так мы можем узнать только об 1 ошибке.
154: А остальные останутся ненайденными. Вот тоже не очень хорошо. И, ну, ещё у нас сообщение об ошибке было странненькое оно, ну, мы видим какую-то надпись, какой-то фрагмент кода, непонятно что там произошло. Ну и представьте, что у вас та
155: 1000 Тестов на проекте. Если вы будете видеть такие ошибки, вам будет тяжело понять. А вы помните, проекты могут там быть из сотен, из тысяч модулей. Вот, и хотелось бы какую-то штуку написать, которая, ну, которая
156: Будет работать более удобно, которая запустит все тесты, и даже если какой-то из них упадёт, то она все равно запустит остальные. В общем, такую штуку, чтобы сообщения об ошибках были понятны ещё было бы неплохо, если бы она писала какие-то человекочитаемые имена Тестов.
157: И писала какую-то статистику, сколько у вас всего Тестов, сколько прошло, за какое время они выполнились. В общем, хорошая новость в том, что такие штуки уже написаны, их много. Ну понятно, что это задача про написание Тестов.
158: Как бы не мы первые, кто с ней столкнулись, и, в общем, инструментов полно. Я вам буду показывать инструмент, который называется джест. Его можно добавить в проект легко нпм инсталл джест, скорее всего.
159: Многие из вас на самом деле с ним работали. В общем, я покажу сейчас, как его применить вот к той информации, о которой мы сейчас говорили. Вот я добавил джест, давайте я в jason добавл.
160: В команду тест. Ну чтоб нам не набирать каждый раз. В общем, добавлю запуск этого инструмента, когда вы его устанавливаете, у вас появляется консольная утилита джест и дальше ей можно передать точно. Ну, если вы её просто запустите.
161: Она найдёт все файлы с тестами по там определённой маске. Вот. Либо вы можете передать ей конкретный файл, и она тогда будет запускать тесты из него. Так.
162: Теперь смотрите, нам нужно немножко переписать код наших Тестов, чтобы он был для нас более удобным.
163: Jazz предоставляет нам вот такую глобальную функцию ит, которая, при помощи которой можно описать тестовый сценарий, она принимает 2 параметра. 1 параметр это человекочитаемое название теста, именно это
164: Название будет отображаться в отчётах, ну, которые вы будете видеть после выполнения, и его можно писать там, в том числе на русском языке. Главное, ну то есть его суть в том, чтобы вам было понятно, что проверяется в этом тесте. Вот. И 2 аргументом вы передаёте
165: Туда функцию, которая содержит код вашего теста. Это вот тот код, который будет запускаться для проверки. Я просто смотрите, копирую содержание нашей вот этой тестовой функции.
166: И вставляю вот прямо сюда без изменений. Дальше давайте я сразу 2 тест тоже адаптирую.
167: Вот я назвал его тоже по-русски, можно отмечать элементы по индексу и копирую этот код в него вот у нас 2 функции it, вот эта вся обвязка нам уже становится не нужна, просто удаляя.
168: Вот и давайте теперь мы это запустим. Нпм тест.
169: Смотрите, у нас запустилась утилита джест, что она написала. Во первых, она написала, что все тесты, что были запущены тесты из этого файлика и что все тесты прошли успешно. Дальше оно вывело список всех Тестов.
170: И показала галочкой, что, ну, каждый конкретный тест о том, что он прошёл успешно. И в конце тут есть общая статистика, сколько файлов с тестами есть в проекте, сколько всего Тестов было запущено, за какое время.
171: Они прошли. Давайте попробуем сломать наш тудулист и посмотрим, как это выглядит. Вот я его сломал, запускаю тесты. Вот мы видим, что
172: Тесты запускались из файла, те джиэс, тесты суммарно, ну хотя бы 1 тест упал. То есть мы не можем сказать, что они все прошли дальше, мы видим список Тестов, видим, что несмотря на то, что 1 тест упал, 2 тест все равно выполнился, и мы вот
173: По этому списку видим, что конкретно упало и что конкретно прошло успешно. Вот также мы в конце видим список всех упавших Тестов и видим их сообщение об ошибке. Вот сообщение по прежнему не очень красивое.
174: И не очень понятно, потому что мы как бы не меняли код наших Тестов, мы просто тут генерируем исключения, но в целом уже кажется, что намного лучше. Ну, по крайней мере, у нас не будет ситуации, когда мы что-то написали, оно не запускается на самом деле. Вот давайте
175: Ещё улучшим наши тесты и сделаем понятные сообщения об ошибке джес предоставляет тоже для этого удобный api.
176: Смотрите, я переписал нашу проверку немножко в другом виде. Тут я использую глобальную функцию экспект в неё я передаю результат выполнения нашего сценария. То есть мы добавили айтим его
177: Результат это внутреннее поле, items, в него добавился новый элемент, и для того, чтобы было удобнее тестировать, я ещё каждый айтим промапил, ну, при помощи функции map преобразовал в его имя. То есть у нас вот функция.
178: Spec передаётся текущий, ну, массив строк это название дел в нашем туду листе. Дальше я использую функцию ту контейн и которая проверяет, что в массив входит
179: Заданный элемент. Если заданный элемент входит, значит тест прошёл успешно. Если заданный элемент не входит, то тест упадёт. Вот, и я проверяю. То есть таким образом, что после того, как мы добавили, элемент тудулист в его списке элементов содержится
180: Хотя бы 1 с вот таким именем. Давайте я эту предыдущую проверку удалю и запущу ещё раз.
181: Наш тест. Смотрите, сообщение об ошибке стало уже более понятным. Во первых, тут отображается функция типа, какая конкретно проверка упала, какое условие упало. Во вторых, тут отображается значение, которое мы ожидали.
182: И значение, которое было на самом деле. То есть мы говорим, что у нас есть initial айтим, ну то есть массив из 1 элемента инишл айтим, который мы передали. Вот, и мы говорим, что мы вот в этом массиве ожидали встретить элемент тест.
183: Его там нет, поэтому тест упал. Вот. Кроме того, мы видим тут кусок кода, в котором отображается прям конкретное место теста, ну в котором произошла ошибка. Вот когда мы генерировали исключение, то у нас отобра
184: Просто начало теста, потому что у нас тест это функция, в нём произошло исключение, и как бы весь тест упал. А тут мы видим как бы конкретное место, которое упало. Если в вашем тесте несколько проверок, вы увидите конкретную типа, которая не прошла. Вот
185: Давайте я сразу поменяю другую проверку.
186: Точно также у нас в данном, ну, когда мы отмечаем элемент галочкой, нашим результатом нашего сценария является признак отмечен элемент или нет, и мы проверяем, что он в нём содержится значение, которое
187: Если привести его к логическому значению, будет значением true вот, в общем, давайте сейчас починю обратно тест, проверим, что что все починилось потом.
188: Отвечу на вопросы и потом пойдём дальше. Так вот, вы видите, что все починилось, я смотрю.
189: Сервис, в котором можно писать вопросы. Кажется, там ничего не пришло.
190: В общем, если вы о чем-то хотите спросить, то, ну в общем, запомните это и сейчас, когда будем, когда мы пойдём дальше, запишите это туда, я в следующий раз постараюсь. А нет, вот пришли вопросы.
191: Так что такое тестирование с помощью снимков и где, зачем его применяют? Давайте про этот, это хороший вопрос. Мы погово.
192: Говорим про него чуть позже. Мы будем дальше обсуждать, как тестировать интерфейс, и там будет больше контекста. Про это и обязательно расскажу дальше, сколько времени при оценке задач вы закладываете на написание Тестов.
193: Трудно сказать, очень зависит от конкретной задачи. Если прям грубо предположить, в среднем, мне кажется, там 10 или 20% может быть. Но это очень сильно зависит от задачи.
194: Так, применяются ли какие-то библиотеки для юнитест? Ну, собственно, я сейчас вам показывал библиотеку джест. Я знаю, что, ну, мы сейчас говорим про тестирование фронтенда, поэтому это все будут библиоте.
195: На джаваскрипте просто тут написан например g unit я знаю, мне казалось что это для джавы вот мы ну в нашей команде используем джест в другой команде, тоже в яндексе в которой я работал применяли другой фреймворк называетс.
196: Мокка тут есть в вопросе тоже. Ну, список примеров библиотек тест энджи. Я предполагаю, что это библиотека для тестирования приложений на ангуляре. Её мы не применяем, потому что у нас в яндексе есть
197: Договорённость что мы весь фронт разрабатываем на реакте вот про react будет потом дальше раздел лекции и я покажу вам поподробнее там как мы пишем тесты. Дальше пример.
198: Про цену ошибки звучит анекдотично. Есть ли реальные случаи, когда юни тесты ловили подобные баги? Не перевешивает ли стоимость человека часов на написание Тестов? Потерю от бага в продакшене? Ну.
199: Не знаю, что, как, если коротко, да, были случаи, когда юниттесты находили серьёзные баги, перевешивает или не перевешивает. Ну, зависит от проекта, очевидно. Ну, суть.
200: Вот этого примера была в том, что чем больше у вас нагружен проект, тем больше цена, ошибки и проекты бывают очень разные по размеру. Если вы пишите там проект, у которого 100
201: Пользователей в месяц, то вы можете, конечно же, не тратить на это время, и вам выгоднее будет там быстрее поставлять код. Ну, стоит, я, конечно, утрирую. Ну, если у вас, грубо говоря, небольшое количество пользователей, то вам может быть выгоднее
202: Не быстрее поставлять код в продакшен, чтобы быстрее решать их проблемы, пусть даже с багами, но вы, типа, быстро поставляя код, получите, принесёте вашим пользователям больше пользы, если у вас там гигантские приложения. Вот как я говорил про
203: Страницу поисковой выдачи, то там прям очень серьёзно относятся к качеству, потому что там, ну, каждый маленький баг может, ну, в смысле, про потерю денег это не шутка.
204: На маленьком баге можно потерять много денег. Вот надеюсь, я ответил на вопрос. Если не ответил, то там, не знаю. Напишите. Ну какой, что ещё хотите уточнить?
205: Так, вопросов вроде больше нет. Давайте, давайте вернёмся обратно. Так, это наш проект.
206: Так, вы можете потом вообще в лекции, тут есть синий текст с подчёркиванием, это ссылки. Можете потом скачать лекцию и потыкать. Ну, следующая тема будет про внешние зависимости.
207: Представьте себе, что вы работаете в авиакомпании, и ваша задача, ну, тестировать пилотов, которые приходят к вам на работу. То есть, вот к вам приходит человек, показывает вам документы из там, лётной школы и какой-то, не знаю,
208: Книжку. Вот, и вы хотите проверить, действительно ли этот человек будет хорошо выполнять свою работу там, как он будет пилотировать самолёт, действительно ли у него есть такой опыт. Вот, и как по хорошему можно
209: Протестировать пилота. Ну, по честному. Вам нужно посадить его в самолёт, дать ему какой-то маршрут. Ну, чтобы он взлетел из 1 города, там долетел до другого города и успешно посадил. Если он это сделал, значит, все хорошо и
210: И, значит, там он умеет действительно пилотировать самолёт. Можете брать его на работу. Вот какой недостаток у этого способа. Во первых, этот способ очень дорогой, потому что самолёт жрёт там какие-то тонны горючего. Ну, это дорого.
211: Во вторых, большая цена ошибки. Если, ну, вам пришёл, к вам пришёл пилот, который как бы не очень хорошо, ну, не очень хороший профессионал, то тогда он может вам разбить самолёт. Самолёт, как бы
212: Стоит очень дорого, пилот умер. Это тоже как бы так себе ситуация. В общем, большая цена ошибки. Вот. И ещё 1 как бы серьёзный недостаток такого тестирования в том, что все ваши пилоты, которые приходят
213: Потенциально могут быть протестированы в разных условиях. И вы не можете влиять на это. Допустим, 1 приходит, там хорошая погода, и ему легко лететь на самолёте. Приходит другой пилот. В это время идёт гроза, и ему тяжелее. То есть вы не можете обеспе
214: Одинаковость этих условий. Кроме того, если вы, допустим, хотите проверить, как ведёт себя пилот, если в самолёте отказал двигатель, то, ну, если сломаете двигатель на реальном самолёте, это как бы может закончиться тоже очень плохо тест.
215: Гарантированно будет очень дорогим. Вот что делают авиакомпании, чтобы, как бы, ну, выйти из этой ситуации, они там разрабатывают или там заказывают у кого-то разработку тренажёров, которые эмулируют
216: Кабину самолёта, то есть он выглядит как настоящая кабина самолёта. Там есть мониторы, которые показывают какую-то ситуацию за окном, там есть, ну почти как настоящие элементы управления, вот эти все штурвалы переключатели, но на самом
217: Деле. Кабина не подключена к реальным двигателям, она никуда не летит, она эмулирует полёт, и пилот, ну, делает вид, что управляет самолётом. А человек, который проводит экзамен, может управлять
218: Там со своего какого-то пульта, той информации, которая будет выдана пилоту, то есть он может эмулировать там отказ двигателя и грозу и так далее. Вот при этом пилот делает Ровно те же действия, которые он делает, находясь в настоящем самолёте.
219: То есть он там управляет штурвалами, принимает какие-то решения, но типа кабина никуда не летит, и за счёт этого тест как бы можно провести дёшево. В общем, к чему это рассказываю.
220: Нам на примере вот этой задачи про тестирование пилотов мы посмотрели важное понятие. Внешняя зависимость. Внешняя зависимость это какая-то штука, которая есть, ну, с которой взаимодействует ваше приложение, которое вы хотите проте.
221: Тестировать и вы не можете этой штукой управлять. Что такое внешняя зависимость? Ну, во первых, это запросы по сети. То есть, когда вот вы написали, допустим, приложение, оно работает на клиенте, оно ходит в какой-то бэкэнд и загружает данные.
222: Вот ваш бэкэнд это внешняя зависимость, потому что он может не работать, и тогда ваш тест упадёт, хотя код работает правильно? У вас в базе могут оказаться неожиданные данные, а если вы запускаете 2 теста подряд, то они могут непредсказуемо их менять.
223: Ну, в 1 и том же бэкенде. В общем, это внешняя зависимость, но на самом деле внешняя зависимость не обязательно связана с каким-то хождением на, ну, запросами на другой компьютер. Внешняя зависимость это, например, функция масс рандом, которая
224: Возвращает случайное число. У вас в приложении может быть какая-то логика, которая завязана на случайные числа. И это значит, что при каждом запуске теста, который проверяет ваше приложение, у вас внутри этой логики будет получаться каждая
225: Раз разное случайное число, и это значит, что ваш тест будет выполняться каждый раз в разных условиях. И это значит, что один и тот же код, который вы не меняли, и который написан корректно, там в 1 случае может пройти успешно, а в другом случае ваш тест может упасть. Вот
226: Ну, ещё пример внешней зависимости, это текущая дата. То есть, если в вашем приложении есть логика, которая завязана на текущую дату, и вы там пишите на это тест, то, ну, это может показаться смешным, но прям
227: Реально много случаев когда не знаю там поставили дату на 3 месяца вперёд ну тот кто писал test думал, что не знаю, это достаточно далёкая дата, она вряд ли когда-то наступит, но потом через 3 месяц.
228: Тест внезапно ломается, потому что текущая дата превысила вот эту захардкоженно в тесте или, например, это тоже как бы реальный случай. И вот в поисковом портале есть
229: Тестирование скриншотами и, ну то есть, когда вы пишите автотест, который делает скриншот вашей страницы, и когда, ну, эти скриншоты где-то хранятся правильные, там в репозитории, когда вы запускаете тест, ну вы внесли какие-то изменения, запустили.
230: Тест, он сделал скриншот вашей страницы и сравнивает его с эталонным. И вот часто на скриншоты попадает какая-то информация, которая зависит от текущей даты. И у дежурного по сервису там 1 января весёлый день, он просто
231: Переснимают все скриншоты. Ну, потому что год поменялся. Ну, это прям вот случай из реальной жизни. В общем, к чему я говорю, если ваше приложение работает с какими-то сущностями, которыми вы не можете
232: Управлять, то вам нужно в тестах изолировать эту внешнюю зависимость, вот поступить так же, как делают авиакомпании, когда они вот делают не настоящий самолёт, ну который, не, ну,
233: Которым можно управлять и который никуда по настоящему не летит. Вот. В общем, 2 понятие, о котором мы сейчас будем говорить, это заглушка в английской литературе называется stub. Это такая вещь.
234: Которая выглядит, ну вот как вот эта ненастоящая кабина самолёта. В общем, заглушка это что-то, что выглядит для вашего кода, как внешняя зависимость, но на самом деле вы можете управлять ей из теста. Вот, и
235: Если очень кратко, то алгоритм тут следующий. Вот у вас есть тестируемый код, у него есть внешняя зависимость штука, которой вы не можете управлять. Например, текущая дата или, например, функция, загружающая данные сервера. Для начала вам нужно
236: Понять какой интерфейс у вашей внешней зависимости. То есть интерфейс это то, как ваш код её видит. То есть если это, допустим, функция random, то интерфейс это функция без параметров, которая возвращает вещественное число от нуля до единицы. Вот.
237: Вам нужно понять, какой есть интерфейс у вашей зависимости, и, возможно, вам нужно немного переписать код вашей внешней зависимости так, чтобы отделить интерфейс от реализации. Дальше вы делаете заглушку, которая
238: Имеет точно такой же интерфейс и каким-то образом должны её подставить вместо настоящей внешней зависимости. То есть так, чтобы тестируемый блок работал с интерфейсом, не зная, как бы, что под ним скрывается. И в тестах вы
239: Вот за этот интерфейс подставляете заглушку, то есть какую-то штуку, которой вы управляете из теста. Надеюсь, что-нибудь было понятно. В общем, давайте это рассмотрим на примере. Сейчас я переключусь снова в редактор кода.
240: Так, секунду.
241: Это наше приложение, которое мы написали в 1 части. Давайте сейчас добавим сюда тест, ну, какое-то поведение, которое использует внешние зависимости, и попробуем написать на него тест.
242: Так это наш тудулист. Я добавляю сюда новый метод.
243: Метод лот по названию. Похоже, что это какая-то логика, которая загружает данные тудулиста с сервера. Смотрите, тут есть Феч, ну функция, которая входит на сервер, это браузерная апи, мы передаём ему какой-то адрес.
244: Дальше, когда, ну, Феч возвращает промис, когда промис разрисовывался, мы получаем сервер, ну, нам приходит какой-то массив строк, массив наших тудайти ов, и мы при помощи функции
245: Мы превращаем каждый массив в туду айтемс и складываем его в поле нашего объекта. Давайте попробуем написать на это тест.
246: Готово. Тест точно такой же, как мы писали в предыдущей части. То есть мы используем функцию ит, которую нам предоставляет жест. Мы указываем человекочитаемое название. И тут точно такие g3 раздела.
247: Подготовка действия и проверка. Подготовка это создание нашего туду листа с какими-то значениями по умолчанию. Тут прям тоже самое. Вот вы можете видеть, что это один и тот же код. Дальше действия, которые мы проверяем. Тут все понятно, мы вызыва.
248: Нашу функцию лод. Вот, и проверка, что тут является результатом нашего сценария, это изменение внутреннего состояния объекта, то есть тоже изменение Айтимов. Окей. Вот он, наш результат, но непо.
249: Понятно, с чем его сравнивать. То есть нам наш метод лот ходит на сервер, получает какие-то данные, и мы должны сравнивать его с этими данными. Но у нас в тесте вот этих данных, с которыми мы будем сравнивать, нигде нет. Вот.
250: Что можно сделать? Давайте немножко перепишем наш тудулист, и чтобы туда можно было поставить какие-то заглушечные данные в тесте. Я Иду в конструктор тудулиста.
251: И добавляю ему вот такое поле Феч. Я присваиваю ему значение по умолчанию глобал Феч. Ну, глобал, это windows, просто наши тесты запускаются в ноде, поэтому я использовал слово global в браузере. Это тоже будет работать. Вот. И
252: Дальше. Смотрите, я меняю метод load так, чтобы он использовал не глобальную Феч, а вот это поле, которое мы только что добавили. То есть в нём по умолчанию лежит та же самая глобальная функция Феч, которую мы использовали до этого. Н.
253: Теперь мы обращаемся не напрямую к нашей внешней зависимости, а к какому-то её интерфейсу, ну, к полю, в котором лежит объект, реализующий интерфейс нашей внешней зависимости. Вот теперь в тесте мы можем
254: Легко подставить вместо настоящей функции Феч заглушку.
255: Смотрите, вот у нас есть экземпляр тудулиста, вот он, у него есть поле Феч, и мы в неё в него присваиваем функцию, ну вот наш Феч это функция, которая возвращает промис, она принимает там какие-то параметры, но для
256: Нашего сценария параметры сейчас не важны. Вот мы присваиваем туда функцию, которая возвращает промис с вот такими 2 айтемами. То есть когда мы вызовем метод load, у нас сработает код на
257: Нашего тудулиста, который вызовет из своего поля Феч вот эту функцию, которую мы в него передали, она вернёт 2 вот этих Атима. И когда промис разрисовывается, мы эти
258: Мы положим в массив items, соответственно, теперь мы можем написать условия, ну, с чем нам сравнивать результат нашего теста, ну, с какими правильными данными нам его сравнивать? Это
259: С вот этим массивом, который содержит строки а theme 1, а этим 2. Давайте это запустим.
260: Так, у нас тест упал, потому что мы ожидали строки айтим 1, айтим 2, а у нас получился какой-то нише айтим. Ну очевидно вот этот вот, в общем, опять же, кто смотрел лекцию предыдущего года, знает,
261: В чем тут подвох? Потому что метод лоут у нас асинхронный. То есть он вот тут сделал запрос на сервер и продолжил своё выполнение. А потом, когда с сервера пришёл ответ, он положил это
262: Поле объекта, то есть вот тут мы сделали метод лот и не дождались выполнения, начали сразу проверять поле объекта. List items вот, чтобы обработать эту ситуацию. Ну, есть много способов, как это можно сделать.
263: Самый простой, наверное, в нашем случае давайте сделаем вот эту функцию нашего теста асинхронной.
264: И после вызова метода лоад напишем команду, чтобы он дождался выполнения.
265: В общем, вот это то, что я вам показываю, это пример того, что джест, ну и вообще другие тестовые фреймворки корректно работают с синхронными функциями, и вы сейчас можете убедиться, что наш тест заработал
266: Вот, все запустил. Видите, что у нас 3 теста и все прошло так, если у вас есть по этой теме вопросы, то пишите их в список вопросов.
267: Сейчас немножко подождём, будут ли вопросы, если, ну, будут, ответим и пойдём дальше.
268: Так, вопросы чем отличаются e2e тесты от интеграционных Тестов это тоже немножко выходит за тему нашей лекции, но если, грубо говоря, интеграционные тесты проверяют ваше приложение.
269: Но не на реальных данных, а, ну то есть те тесты, это тесты, которые проверяют прям настоящий экземпляр вашего приложения с настоящей базой. Вот с настоящее.
270: Kedoo Ровно в том виде, в котором с ним работают пользователи, интеграционные тесты это тесты, которые проверяют все-таки какой то специальный экземпляр вашего приложения, подготовленный для Тестов ете тесты писать.
271: Сложнее, потому что, когда у вас настоящий экземпляр вашего приложения, вам сложнее контролировать его зависимости и его состояние, но e2e тесты могут отловить баги, которые происходят на стыке каких-то.
272: Разных частей вашего приложения, которые, допустим, не участвуют. Если вы пишите интеграционные тесты или модульные, в общем, ну, про это будет дальше ещё в другой лекции рассказ, но типа
273: Если кратко, то e2e тесты более дорогие, ну они очень дорогие в поддержке, но они позволяют отловить большее количество багов, их используют для того, чтобы протестировать какие-то критичные сценарии, где
274: Очень большая цена ошибки.
275: Так, ещё 1 вопрос. Используется ли ii, видимо, искусственный интеллект для тестирования продуктов не используется про это будет, ну, дальше в нашей
276: Раздел там как писать полезные тесты и там будет понятно, почему не используется. Вот. И 3 вопрос, если у нас не класс, а просто функция, как подставлять заглушки.
277: Так, про это будет тоже несколько примеров. А, ну вот они будут, наверное, прямо сейчас. Давайте пойдём тогда дальше и посмотрим их. Так, я переключаюсь обратно на презентацию.
278: Так.
279: В общем, у нас сейчас, мы сейчас с вами попробовали протестировать кусок нашего приложения, которое обращается к внешней зависимости. И мы для этого сделали дополнительные действия, в которых мы меняли код.
280: Самого нашего приложения. В общем то, что мы сделали, называется добавление точки расширения, точка расширения это какой-то специальный апи в вашем продуктовом коде, через который можно поставить заглушки
281: Для внешних зависимостей. Вот, и тут надо упомянуть ещё 1 понятие. Это рефакторинг, рефакторинг, это когда вы переписываете ваш продуктовый код, но при этом результат его работы не меняется. То есть у нас была функция лот.
282: Которая ходит на сервер и которая складывает результат, полученный с сервера во внутреннее поле нашего туду листа. Когда мы переписали код, ну там добавили обращение к полю Феч, мы добавили точку расширения
283: Но при этом результат работы нашего тудулиста не изменился. Вот метод load в продуктовом коде, как работает, ну, он работает точно так же, как и раньше. Вот, то есть мы сделали рефакторинг для того, чтобы добавить точку расширения. Вот, и как раз вопрос.
284: А каким образом можно добавлять точки расширения? Ну, на самом деле очень много вариантов и зависит от конкретно вашего проекта, от конкретного места в вашем проекте зависит, сколькими вариантами можно до
285: Точки расширения. Я сделал слайды для нескольких, мне кажется, таких довольно популярных, в общем, 1 вариант, когда вы передаёте зависимость явно, ну вот.
286: Мы передали зависимость, указали её в поле класса. На самом деле вы могли передавать это в конструктор класса, могли сделать какую-то фабрику, то есть мы создавали экземпляр тудулиста через new тудулист, а вы могли бы сделать фабрику функцию, которая создаёт вам
287: Экземпляры тудулиста и в эту фабрику передавать экземпляр зависимости. А в тудулисте, например, обращаться к нему через замыкание. Вот. Или вы, если вы тестируете функцию, вот о чем был вопрос, вы можете передавать внешнюю зависимость, как
288: Дополнительный, необязательный параметр функции или опять же создавать функцию через фабрику и тоже обращаться к ней через замыкание. Если вот кому-то нужны примеры вот того, че говорю, вы можете, ну как минимум студенты шри могут потом
289: В чатик написать, в шириный. И я там пришлю потом примеров. Вот что ещё можно сделать. А сейчас, прежде чем будем говорить, что ещё можно сделать? Вот этот скриншот, это документация библиотеки редакс обзер.
290: То есть это популярная опенсорсная библиотека, которой пользуется много людей. Там в документации есть специальный раздел, как можно подставлять туда зависимости. То есть вы видите, что там вот есть функция крит, эпик мидлвар.
291: И туда можно передать параметр депенденсис и поставить туда заглушки вместо настоящих зависимостей. То есть это как раз вот такой способ, о котором мы сейчас говорим, когда зависимость передаётся явно
292: Вот что ещё вы можете сделать? Иногда вы можете оказаться в тяжёлой ситуации, когда вы не можете менять интерфейс своих сущностей, вы не можете туда. Ну, у вас нет доступа, нет возможности.
293: Туда что-то передать, какие-то объекты. Тогда вы можете сделать некрасивый такой способ. Можете положить внешнюю зависимость в глобальную переменную, например, на этом слайде представьте, что у вас код, который использует функцию windows матч медиа это функция
294: Которая проверяет на джаваскрипте, выполняется ли сейчас какое-то условие какого-то media квари. То есть вы можете в цссе писать медиа квайрес и делать разную вёрстку в зависимости от ширины экрана, например, или от того дестопы. Это
295: Браузер или мобильный. Вот вы можете точно также такие условия проверять на джаваскрипте, чтобы, например, навешивать какое-то разное поведение. Вот и windows матч медиа это windows, это глобальная переменная матч медиа, это типа
296: Тоже глобальная функция, которой вы обращаетесь через глобальную переменную. Вот по хорошему вам нужно было бы вынести это обращение в какую-то свою функцию и передавать вместо своей функции заглушку, но вы не всегда так можете делать, поэтому вы можете зафигачить её прямо
297: В глобальную переменную. И, ну, это будет плохо, потому что к глобальной переменной может обращаться кто угодно. Это значит, что другие, другой какой-то код, который, ну, выполняется в тестах, он может не ожидать, что там нахо.
298: Заглушка и может от этого работать некорректно, но типа в целом это как вариант, и я показываю этот слайд, потому что, ну, хочу сказать вам важную идею. Всегда смотри.
299: В любой ситуации, какую пользу вы получаете от решения и какую цену вы за это платите? Если польза, которую вы получаете больше, чем заплаченная цена, то тогда, значит, так и делайте, применяйте любые костыли.
300: Главное, чтобы вам было больше пользы. Вот ещё 1 пример. Это такой пример из мира ооп, как можно поставить внешнюю зависимость. Представим, что у вас есть какой-то класс. Допустим, вы пишите плагин.
301: Какой-то системе вы не можете, ну вы пишите его целиком, самостоятельно, но вы не можете менять этот интерфей, его интерфейс, потому что, ну допустим, его параметры конструктора не можете менять, потому что внешняя система ожидает именно такие параметры конструктора и ваш плагин не буде
302: Работать. Вот, а вам надо. В вашем классе используется внешняя зависимость и вам надо как-то это, ну, протестировать и подставить вместо неё заглушку в тестах. Вот что вы можете ещё сделать? Вы можете написать класс, унаследованный от вашего класса и
303: Определить в нём какие-то из элементов, то есть вы можете, например, вынести создание этой внешней зависимости в какую-то функцию. Тут есть в моём в классе май класс функция get депенденси, которая создаёт экземпляр внешней зависимости. Вот вы мож,
304: Можете сделать класс наследник и переопределить там функцию депенденси, которая будет вместо настоящей внешней зависимости возвращать, ну, вашу заглушку, которой вы управляете из Тестов, и тогда вам в тесте нужно будет
305: Создавать экземпляр не настоящего класса, а его наследника. Но так как он наследуется от настоящего класса, у него будет точно такое же поведение, как у настоящего класса, и вы можете его тестировать. При этом вместо настоящей внешней зависимости у него будет заглушка, в общем,
306: Смотрите, мы посмотрели 3 варианта вообще очень разных. Вот передавать, явно передавать там через глобальную переменную, отнаследоваться от класса. Вот есть ещё вот такая ссылка, потом скачайте обязательно.
307: Лекцию и, ну послушай, посмотрите видео, которое по этой ссылке там рассказывается про подход депенденси инжекшн. Это ещё 1 подход, он не только про тесты, а вообще про организацию зависимостей.
308: В вашем приложении, как организовать взаимодействие между модулями, так между модулями, так, чтобы количество взаимодействий было небольшим и чтобы вам было легко этим управлять. В общем, посмотрите, пожалуйста, это видео, это будет вам полезно. Это ещё 1
309: Как бы способ, как можно передать какие-то управляемые заглушки вместо настоящих внешних зависимостей.
310: Так, смотрите, мы поговорили с вами про автотесты в целом. Ну для чего они нужны, как они помогают? Почему их важно писать дальше? Мы с вами написали простой тест. Понятно, что там интересного было мало, это просто какая-то функции.
311: Которая проверяет очень примитивный код наш тудулист. Но на примере этого простого теста мы разобрали вообще основные идеи, как надо думать о содержимом тесте, о том, что надо ответить на вот эти 3 вопроса о том, что
312: То есть есть 3 части подготовка действия и проверка. Вот, и мы познакомились с фреймворком джест это такой дополнительный инструмент, который делает написание ваших Тестов более удобным. Дальше мы поговорили о том, как
313: Тестировать код, который обращается к внешним зависимостям. Вот и следующая наша тема тоже связана с внешними зависимостями, но чуть более сложными.
314: В общем, наверное, вы обратили внимание, что вот я в начале говорил про 3 типа результатов Тестов, про явно возвращаемые значения через return про
315: Внутреннего состояния системы и про обращение к внешним системам. Но в наших примерах вот все, что мы рассматривали, мы видели, ну, использовали только результаты первых 2 типов, а про 3 как-то не говорили. Вот это неспроста, потому что, как правило,
316: Тесты, которые проверяют результат 3 типа, более сложные, чем для первых 2 типов. И они более хрупкие, их тяжелее писать, тяжелее отлаживать. И вот таких Тестов лучше избегать, если у вас есть сценарий, который вы можете
317: Протестировать, проверив возвращаемое значение или изменение внутреннего состояния, то лучше так и сделайте. Вот. Но есть некоторые сценарии, когда проще проверить, ну, намного проще проверить результат 3. Тип.
318: Давайте вот про них поговорим. Представьте себе, что вы тестируете систему Полива, то есть какой-то компьютер, который получает информацию с датчиков, получает информацию о погоде, и он управ.
319: Насосом, поливающим дерево, то есть он выдаёт в насос сигнал, там включить его или выключить там по какому-то своему алгоритму. И вам надо проверить, что эта система Полива работает правильно, какое тут будет.
320: Ну, типа, что нам нужно проверять, если мы хотим протестировать изменение состояния нашей системы, но очевидно, что состояние это влажность почвы под деревом. То есть мы запускаем наш тест, ну, нашу систему.
321: Допустим, на на целый день она там когда-то включается, когда-то выключается из за этого меняется из за того, что работает насос, меняется влажность почвы под деревом. И мы в конце дня меряем её датчиком и на основании этой информации определяем, прошёл наш
322: Тест или нет, правильно работает система или нет. Очевидно, что такой тест будет очень неточны. Ну, даже у него много недостатков. Во первых, он будет длиться целый день, во вторых, он будет очень неточным, потому что если система забыла включиться там на
323: 15 минут. Или она, например, включилась там на 15, ну, на 15 минут позже или раньше, то, измеряя влажность почвы. В конце дня, мы вряд ли об этом узнаем. Вот. И что тут можно сделать. Мы можем вообще всю вот эту
324: Часть про насос и дерево убрать из нашей системы и подключить к компьютеру специальный регистратор, который будет запоминать, как, какие команды ему были поданы и в какое время.
325: Так, а в общем, тест с таким регистратором будет сильно более точным, потому что если, допустим, насос должен, ну,
326: Команда, которая включает насос, была подана, допустим, на секунду позже, то в регистраторе запишется другое время. И в конце мы, когда смотрим на log этого регистратора, мы сможем увидеть, что система отработала неправильно. Вот. И тут
327: Ключевое отличие от Тестов, которые тестируют сценарий первых 2 типов в том, что мы смотрим для принятия решения о том, прошёл тест или нет, не на ту систему, которую тестируем, а на какую-то, на какой-то вот этот регистратор.
328: Это такая как бы умная заглушка, запоминающая, состоя, запоминающая с какими параметрами и в какое время были обращения к ней. Вот, ну то есть ключевая ключевое отличие Тестов, которые
329: Проверяет результат 3 типа в том, что мы добавляем туда специальную заглушку, которая выглядит точно так же, как наш насос. Насос это внешняя зависимость тоже вот она выглядит точно так же, как наш насос, она принимает те же команды.
330: Но она запоминает, с какими параметрами было к ней обращение, и мы смотрим на нашу заглушку для того, чтобы понять, отработал тест или нет. Звучит, наверное, не знаю, может быть, не очень понятно. Мы сейчас попробуем это написать.
331: Важное правило, что в 1 тесте должно быть не больше 1 такой заглушки. То есть у нас были как бы тупые заглушки, которые просто предоставляют данные, ну, управляемые из теста.
332: Внешней зависимости, и они назывались стабы. Вот умные заглушки в англоязычной литературе называются моки. И вот они запоминают обращение к ним, и мок должен быть только 1 на тест. Почему? Потому что если вы хотите сделать несколько
333: Значит, это несколько. Ну, вы по каждому из них можете принять решение, прошёл тест или нет. А это значит, что вы тестируете в 1 тесте несколько сценариев, а мы говорили, что нужно в каждом тесте проверять Ровно 1 сценарий. Поэтому вот супер важное правило.
334: Давайте так, давайте снова переключимся в наш редактор кода и напишем тест, который возвраща, ну, добавим в наш тудулист логику, которая производит результат треть.
335: Типа, то есть обращение к внешней системе и протестируем её.
336: Так.
337: Я Иду в наш тудулист и добавляю туда ещё 1 команду.
338: Это команда сейф, она тоже ходит на сервер. Ну, по названию похоже, что она сохраняет текущий список дел в какую-то ручку на сервере. Вот. Плюс тут есть логика, она сохраняет только те элементы, которые ещё не чекнуты.
339: То есть то, что мы отмечили, отметили, как выполненное на сервер передано не будет. Вот. И она берет, она тоже использует функцию Феч, тоже обращается к ней не напрямую, а через наше поле. Ну,
340: В нашем классе вот оно вызывает её с каким-то адресом и передаёт туда какие-то параметры. Давайте напишем на это тест.
341: В общем, точно также используем функцию ит пишем нормальное человекочитаемое название. Точно также у нас 3 стадии подготовка. Это мы создали тудулист, действие, которое мы проверяем. Мы вызвали команду сейф. Вот, и у нас 3 стадия.
342: Проверка, но в отличие от предыдущего примера, то есть там нам хотя бы было понятно, что является результатом, а тут нам даже непонятно, что будет результатом. Вот, то есть с чем сравнивать, непонятно и что
343: Мы хотим сравнить. Непонятно. Давайте.
344: Так, вспоминаем про вот эту систему с деревом, то есть нам надо сюда подставить вот этот регистратор, который будет запоминать, с какими параметрами обращались функции Феч. Давайте это напишем.
345: Вот мы присваиваем функцию Феч, какую-то функцию, возвращающую промес. Вот, и теперь нам надо как-то сделать, чтобы мы запоминали параметры, с которыми к ней обращались. Это сделать не сложно.
346: Делаем переменную.
347: В нашу функцию Феч будут приходить какие-то параметры, и мы просто через замыкание обращаемся к нашей локальной переменной внутри теста и запоминаем с каким параметр, ну запоминаем её в локальной переменной. То есть когда
348: Мы вызвали сейф, он внутри вызовет зис Феч. Для того, чтобы сохранить данные на сервер, он передаст туда какой-то url. Ну и мы сохраним его в нашу локальную переменную тогда.
349: Если мы хотим проверить, что у нас обращение к серверу было правильным, то мы наш вот этот икс икс, это результат, это лог нашего регистратора, в него записано с каким, с какой
350: Информации было обращение к нему. Вот он является результатом работы нашего сценария, и мы его сравниваем. Ну, мы ожидаем, что в нём будет. Мы ожидаем, что в нём будет адрес. Вот это
351: Давайте попробуем это запустить.
352: Так у нас, а я немножко ошибся у нас. X это локальная переменная внутри нашей заглушки, а переменная, в которой мы сохраняем, это arx.
353: Так вот, мы видим, что у нас тест прошёл. Давайте попробуем что-то сломать. Вот представим, что у нас поменялся код и мы начинаем обращаться на некорректный адрес.
354: Мы запустили наш тест. Вот он говорит, что упал тест на сценарий. Можно сохранять элементы на сервер и ох.
355: Опечатка.
356: В общем, упал сценарий, который говорит, что можно сохранять элементы на сервер, и говорит, что пришло неожиданное значение адреса в нём оказалась лишняя единичка.
357: Смотрите, мы сейчас сделали заглушку, вот эту умную заглушку, мог, сделали её на коленке, написали как бы сами эту функцию, которая запоминает в локальную переменную. На самом деле нам, скорее всего, в работе
358: Понадобятся какие-то более сложные вещи, то есть нам надо запоминать, допустим, не 1 вызов, а все вызовы, а ещё наша функция, к которой мы обращаемся, может возвращать какие-то значения, и нам нужно уметь настраивать заглушку так, чтобы она возвращала какие-то
359: Ожидаемые значения для нашего кода вот и jest содержит уже готовые api для конструирования таких заглушек, то есть вы можете через api джеста создавать эти заглушки, настраивать там, какие значения они возвращают.
360: И там много разных возможностей. Вот. Поэтому, если вы будете этим пользоваться, то лучше там изучите документацию. Так, смотрите, мы поговорили сейчас про тестирование.
361: Результата 3 вида обращения к внешней системе. Дальше у нас по плану ещё 1 демо это тестирование реакт приложений. Давайте, наверное, сейчас сделаем небольшой перерыв. 5 минут и продолжим. Кажется, что
362: Все устали, много информации. Вот.
363: Мы продолжаем лекцию по модульным тестам. Пришли вопросики, давайте их зачитаю и ответим. 1 вопрос чем отличается мок от стаб? Мы про это говорили сейчас в лекции.
364: Стабом называют заглушку, в которой нет никакой логики, которая подставляет в ваш тестируемый код какие-то значения, которые вы ожидаете в тестах, мог. Это умная заглушка, которая она тоже может подставлять.
365: Тестовое значение в ваш код, но она ещё и запоминает, с какими параметрами к ней обращались. И когда вы пишите тесты, проверяющие результат 3 вида обращения к внешней системе, то вы, вы используете, мог для, ну, информацию.
366: Он запомнил для того, чтобы понять, прошёл тест или нет, и вы помните правило, что каждый мог, ну, в 1 тесте нужно создавать не больше 1 мока, потому что если хотите создать несколько, то это значит, что вы тестируете в 1 тесте несколько сценарие.
367: Дальше. 2 вопрос. Для метода лот пришлось изменить код в туду лист. Это нормальная ситуация. Это хороший вопрос. Вот на каждой лекции спрашивают, корректно ли писать в продуктовом коде.
368: Какой-то специальный код, который нужен только для Тестов. Тут, смотрите, нет такого ответа, что это корректно или это некорректно? Вот когда вы пишите код, вы получаете от этого какую
369: Пользу и платите за это какую-то цену. Очевидно. Ну какую цену вы можете платить? Если вы пишите больше кода, значит вам тяжелее будет в нём разобраться. Значит у вас будет более сложная логика и больше мест, где ваше приложение
370: Может сломаться. Значит, когда вы запускаете сборку приложения, ваше приложение будет собираться чуть чуть медленно. То есть, если вы там в каждой задаче, там на протяжении года пишите немного дополнительного кода, то ваше приложение к концу года будет
371: Собираться значительно медленнее и это относится не только к тестам, а просто к любому коду, когда вы что-то хотите улучшить без явной необходимости. Вот, то есть, когда вы пишите код, вы не, ну вы платите за это цену, это не проходит.
372: Бесследно. Вот теперь, если вы пишите код, который позволяет ваше приложение протестировать, то вы получаете от этого пользу в том, что можете автоматизировать проверку вашего приложения и не делать её вручную.
373: Соответственно, если вы видите, что польза, которую вы получаете больше, чем тот, чем та плата, ну, за ваши действия, которые вы делаете, то, значит, ну, делайте эти действия.
374: И значит, пишите в продуктовом коде любой код, который вам в чем-то поможет. Надеюсь, я ответил на этот вопрос дальше. Как сделать несколько файлов для Тестов?
375: Жест и выполнить их последовательно. В общем, это очень легко. Ну там все описано в документации джеста, но если кратко, вы можете перечислить эти файлы просто как параметры. Но если вам нужно там, например, 2 файла запустить и
376: Запустить тесты из определённых там из определённого небольшого количества файлов. Вот более распространённый способ, когда вы называете файлы по какому-то правилу, например, добавляете туда суффикс не просто jazz, а суффикс, тест, джес и
377: Вот по этой маске вы можете задать джест в параметрах маску, по которой он будет искать файлы внутри проекта и запускать все файлы, которые найдёт. Вот надеюсь, я ответил на вопрос.
378: Так, на каком этапе разработки стоит настроить запуск автотестов на этапе пуша, репозиторий или какого-то пулреквеста? Тут, в общем, зависит от вашего проекта. Может быть. Ну, у вас
379: Может быть такой проект, на котором автотесты вообще не нужны. Например, если вы, вы его пишите очень срочно и после использования переса, ну как бы выбросите его. То есть он решает какую-то краткосрочную задачу, то там можно вообще тесты не настраивать.
380: У меня, ну вот в проектах, над которыми я работаю, настроены авто, ну там настроен скрипт, который запускает автотесты всего проекта, и он запускается и в поревести. То есть когда кто-то хочет влить какие-то изменении,
381: Он создаёт пуллреквест и там в том числе запускаются автотесты. Вот. И 2 момент, когда запускается скрипт, это перед релизом. То есть, когда вы вливаете пулреквест, там находятся ваши изменения, ну, есть какой-то diff с основной веткой, вот эти
382: Ваши изменения, и вы проверяете, что ваши изменения работают корректно. Когда вы вливаете, ну, когда вы собираете релиз, то у вас в основной ветке находится несколько пуллреквестов разных разработчиков, и вам нужно проверить, что они
383: Не корректно работают вместе друг с другом. То есть каждый из них мог работать корректно, но в результате, когда там они мержились, могло что-то сломаться. И вот поэтому нужно перед релизом тоже запускать автотесты. Вот на самом деле
384: Есть ещё много разновидностей, ну, много как мест, где это может принести пользу. Например, есть методология тест драйвин девелопмент, когда, то есть разработка, управляемая тестами, когда вы тесты вообще пишите до того, как
385: Писать код вашего приложения, то есть чтобы вам написать тесты, вам, вам не обязательно все это реализовывать. Вам достаточно написать интерфейс, с которым будут взаимодействовать тесты и делать с ними какие-то действия. Вот вы пишите интерфейс, потом сразу пишите тесты, в которых
386: Вы кодируете ваши требования, то есть вы пишите в тестах такие проверки, которые пройдут тогда, когда ваше приложение начнёт реализовывать ваши требования. Ну, вашего сценария. Вот. И понятно, что так как у вас приложение не реализовано, то тесты сначала не
387: Проходят. Вот вы написали интерфейс, написали тесты, запустили там джест в фоновом режиме, и потом начинаете разрабатывать приложение и наблюдать, как тесты 1 за 1 начинают зеленеть. Ну, в общем, это такая как бы методология.
388: Разработки, она там имеет некоторые плюсы, некоторые минусы, но вот в каких-то ситуациях её тоже удобно использовать. Ну как есть. Я знаю, что те, кто её используют, говорят, что
389: Из за того, что они пишут тесты в начале, им становится легче писать код, потому что, продумывая тестовый сценарий, они структурируют у себя в голове, то, ну, информацию о предметной области, которую им надо запрограммирова.
390: Вот я, я лично не использовал.
391: Как-то так.
392: Так, вроде это все вопросы, которые есть у меня в списке. Давайте пойдём дальше.
393: Так, я сейчас переключусь ненадолго на слайды посмотреть, что там есть интересного.
394: Так, а, ну в общем, у нас была 3 часть про тестирование взаимодействия. Сейчас мы тестируем реакт приложение, так, переключаюсь тогда обратно.
395: Смотрите, это тоже вес код. И я думаю, что сейчас будет повеселее, потому что сейчас будет похоже на прям реальную работу разработчика. В общем, я написал для лекции небольшое приложение, это тоже тудулист. Ну то есть нам нужна просто
396: Какая-то предметная область, на которой мы будем экспериментировать. Мы сейчас с вами разбирали тудулист, поэтому мы хорошо понимаем, как работает вот просто тот тудулист, который мы тестировали до этого. Это был просто какой-то абстрактный класс, который куда-то сохраняет информацию. Ну он
397: У неё не было никакого пользовательского интерфейса. Вот, а вот этот тудулист, это на реакте. В общем, давайте вот посмотрим на него. Вот видите, тут 2 странички есть home и about what у них, ну,
398: Меняется адрес вот эбаут, вот хоум home, это Корнеевой адрес нашего приложения, тут все работает на клиенте я ввожу какой-то текст, нажимаю добавить вот он добавился, если я ставлю
399: Галочки, они зачёркиваются. Если я переключаюсь между страничками, состояние сохраняется, потому что там, ну, я надеюсь, у вас была лекция по реакту и то, что буду рассказывать, вы будете понимать, если не будете, то напишите, пожалуйста, куда
400: Нибудь в комментарии в зум и я тогда подстроюсь в общем, тут все написано на реакте для переключения Урлов используется react, роутер для хранения состояния используется редакс, ну то есть есть общий стор на все приложе.
401: И мы сейчас будем писать на это тесты. Давайте посмотрим, что есть в нашем проекте. Этот проект создан через create реакта, поэтому тут какой-то типа шаблон по умолчанию. Вот тут есть
402: Папка срц и в ней, ну, точка входа это индекс ттс икс файл что он делает? Он создаёт наш редакс стор и рендерит наш аппликейшен аппликейшен это red компонент.
403: Его в 2 такие обёртки это browser роутер из библиотеки реакт роутер дом. И это провайдер, который делает доступным стор внутри всех вложенных компонентов. Вот функция, создающая стор. Ну тут какие-то
404: Auction. Редюсеры. Надеюсь, вы вам знаком, редакс? И, в общем, вы примерно понимаете, что тут происходит дальше? Наш индекс ттс икс рендерит компонент?
405: Application вот он, этот компонент, имеет сверху вот эту панель со ссылками вот home и about. И тут используется компонент линк из react роутера также.
406: Он имеет 2 вот таких роута с шаблонами шаблон эбаут в общем если адрес совпадает с about он рендерит компонент эбаут из вот из папки pages вот он.
407: Если адрес совпадает со слэшом, то он рендерит компонент хоум тоже из папки pages вот папка пейджес вот они 2 компонента то есть тут просто какой-то контент без какого-либо поведения на домашней страничке есть ещё дополни.
408: Туду лист это тоже react компонент вот он лежит в Папке components, это лист, у которого сверху панель с инпутом и кнопкой и внутри какой-то список Айтимов.
409: Мы тоже в виде компонента, у них там навешивается какой-то класс, ну который зачерки, если вы ставите галочку, он зачёркивает надпись. Вот. И, собственно у него есть текст и чекбокс.
410: Как-то так. Давайте напишем на это тесты. Я сейчас сделаю, ну я буду в тестах создавать весь аппликейшен. Помните, мы говорили, что модули могут быть любого размера, в том числе модулем. Может быть все ваше прило.
411: В общем, для простоты будем сейчас считать, что как раз модуль это все приложение.
412: Я тут тут сейчас был вопрос, как сделать, чтобы джест автоматом, ну, находил файлы и мог запускать много файлов. Вот сейчас я назвал аппликейшн тест ттс икс и jest должен автоматом его запустить. Вот теперь смотрите.
413: Мы создали наше приложение через crop и этот шаблон приложения уже содержит средства для модульного тестирования, то есть тут в пк джисон есть много разных библиотек, а и ещё такой момент.
414: Я сделал приложение на тайпскрипте, чтобы поудобнее было его писать, чтобы был автокомплит и проверка тайпингов. Я надеюсь, что вам тоже это знакомо. Если для кого-то эта проблема, ну очень мешает понимать, то, пожалуйста, напишите это я.
415: Постараюсь в лекции, ну, рассказывать больше информации так, чтобы все равно вам было понятно. Вот для начала вот мы создали пустой файл с тестами. У нас уже настроен джест.
416: Потому что он при создании проекта из шаблона, он автоматически настроен для начала нам нужно импортировать функции вот эти it i expect, которые мы будем использовать для Тестов.
417: Мы импортируем их из модуля джест глобалс дальше ну, давайте проверим тот же сценарий добавления элементов, напишем вызов функции it для нашего теста.
418: Пока что это ничем не отличается от наших примеров. То есть мы вызываем глобальную функцию ит, которую мы импортировали. Дальше мы передаём туда человека, читаемое название нашего теста и передаём туда какую-то функцию
419: Которая будет содержать логику нашего теста. Теперь нам нужно создать внутри теста экземпляр нашей тестируемой сущности, и мы говорили, что наша тестируемая сущность это react приложение, как мы это сделаем.
420: Мы сюда вставили вот практически тот же код, который мы видели в индексе. Давайте переключусь. Вот мы создали стор, у нас переменная стор. Дальше мы сделали приложение, которое, ну,
421: Компонент аппликейшн, обёрнутый в браузер роутер и в провайдер. Вот тут все подчёркивает красным, потому что у нас ничего это не импортировано. Сейчас я это добавлю.
422: Вот, все окей. Вот мы создали наш аппликейшн, и дальше смотрите, в индексе мы передаём его в функцию реакт дом рендер. Ну тут 16 реакт, по моему, в этом шаблоне, из которого создавал
423: В общем, тут функция реак дом рендер в тесте мы импортируем из специальной библиотеки Тестин лайбрери, хелпер рендер и передаём наш вот этот application специальный хелпер. В общем, для чего это?
424: Нужно. Наше приложение работает в браузере, оно использует для, ну, оно использует библиотеку реакт, которая использует дом апи браузера для того, чтобы создавать дом, элементы, там, навешивать на них обработчики событий и как-то этим управлять. Вот этот
425: Дом апи и вот то, что есть в браузере, это большая внешняя зависимость нашего приложения. Когда мы запускаем тесты, они запускаются без браузера, они запускаются в not jazz i. Там никакого вот этого дом апи нет, поэтому
426: Нам для вот этой большой внешней зависимости нужно сделать большую заглушку, которая будет эмулировать в наших тестах апи браузера. Эта заглушка уже готова, я не сам её писал, а взял готовую библиотеку джиэс, дом джаваскрипт дом.
427: Вот и библиотека тестинг лайбрери как раз содержит набор хелперов, которые позволяют рендерить приложения там для написанные на различных фреймворках, например, на реакте с помощью
428: Вот этого ненастоящего дом апи. То есть вот эта функция render отрендерит наше приложение application без браузера, используя библиотеку, джис дом. Вот.
429: У этой библиотеки api точно такой же, как у элементов браузера, то есть вот мы верну ну, функция render вернула нам какой-то контейнер, и если мы посмотрим, какие у него есть методы, у него есть методы. Вот квари, селектор, квари, селектор ол.
430: Ну, это прям такие же методы, как у дом элементов браузера.
431: Можем вывести, например, в консоль и на давайте это, кстати, сделаем.
432: Вот смотрите, что мы сделали. Мы создали экземпляр нашей тестируемой сущности нашего приложения, потом мы через команду рендер отрендерили его, ну, без браузера, как бы в памяти нашего теста, и вывели это в консоль. Давай.
433: Я напишу, ну, запущу джест и посмотрим, что выведется.
434: Вот видите, тут отрендерился html, и тут прям наша страничка, ну, тут страничка, у которой есть ссылка хоум, ссылка эбаут, есть заголовок h1 home и есть наш тудулист. Вот.
435: Теперь мы вот в нашем контейнере имеем экземпляр нашего приложения, нам нужно с ним выполнить какие-то действия. Давайте попробуем что-нибудь ввести в текстовое поле, то есть у нас вот
436: Есть текстовое поле.
437: Так вот оно импут и с пустым велью. Давайте попробуем в него что-нибудь ввести. Для этого импортируем ещё 1, ещё 1 хелпер.
438: Из библиотеки тоже тестинг лабери, юзер эвент. Вот такую переменную эвентс. В этой переменной содержится набор команд для эмуляции взаимодействия пользователя с нашим приложением.
439: Отрендеренным. Вот в jazz доме. И мы, мы выбираем тут команду type, то есть ввести какое-то значение в текстовое поле. Тут ей нужно передать 2 параметра. 1 параметр это
440: Элемент, в который мы вводим 2 параметр, это текст, который мы хотим ввести. Вот вопрос, как нам взять, ну как нам найти этот элемент? Мы его могли, конечно, тут написать контейнер, квари селектор и, например, по какому
441: Какому-нибудь классу или по, а могли бы сказать.
442: Сейчас.
443: Ну, там get element by tag name. Ну, в общем, есть способ проще. Смотрите, мы идём в наш компонент, вот он тудулист и помечаем наш импут специальным атрибутом.
444: Data test id и даём ему какое-то название input эд.
445: Дальше вот вместе с контейнером у нас возвращается из функции рендер ещё 1 функция get by test id и мы можем с помощью неё доста.
446: Элементы из контейнера, зная их атрибут тест айди.
447: То есть 1 параметром в type мы передаём элемент, с которым хотим взаимодействовать, a2 параметром передаём текст, который хотим ввести в input.
448: Напоить коня. Смотрите, наш, наше приложение, ну, перезапустилось. У нас джест запущен и висит в памяти. Как только мы сохраняем, он перезапускает наш тест. Вот, и мы видим, что тут появился
449: Появился атрибут value у инпута ну появился атрибут data test id которым мы его пометили и появился атрибут велью у импута и в нём наше значение, которое мы туда ввели вот вот тут в консоли не очень удобно это смотреть, поэтому давайте.
450: Я вам покажу ещё 1 способ. Вы можете вот из библиотеки тестинг лайбрери вместе с командой рендер импортировать объект скрин и
451: Написать вот так screen lock to testing плейграунд url сейчас тест перезапустится и вы увидите, что в консоль вывелся вот такой url у которого тут параметр и там какой-то закодированный текст.
452: 64. Вот если вы его откроете, то вы увидите специальную страничку, на которой, ну, такой инспектор вашей разметки. Вот вы видите, что тут разметка нашего компонента.
453: Тут есть input, есть батон у импута есть напоить коня, есть наш тудулист с нашими элементами. Вот на самом деле тут много всяких прикольных штук. Например, вот тут отрендерена вёрстка, она, конечно, без стилей.
454: Но, по крайней мере, вы по вот этому окну справа можете видеть, что отрендерено на странице. Ещё вы можете кликнуть по элементу, и он покажет там при помощи какой команды можно к нему обратиться. В общем, вот этот
455: Testing плейграунд, очень крутая штука. Дальше вот мы ввели значение в поле для создания нового элемента списка. Давайте теперь кликнем по кнопке. Точно также пишем вен.
456: Клик.
457: Обратите внимание, тут есть ещё там дабл клик и, ну, вообще, если посмотрите, события тут много есть, там вставить из буфера обмена, навести мышку, загрузить файл. В общем, мы кликаем
458: По кнопке опять нам, чтобы обратиться к кнопке, надо пометить её атрибутом дата тест айди. Ну то есть мы могли бы другими способами обращаться, но это кажется очень удобной. Назовём её
459: Эд.
460: Вот и нам нужно передать функцию клик на нашу найденную кнопку.
461: Вот теперь, если мы сейчас посмотрим в нашу песочницу то что мы увидим, что у нас атрибут велью стал пустой строкой. То есть мы, когда кликнули по кнопке, у нас добавился элемент список и значение в импоте очистилось. Вот, и мы видим, что у нас
462: Появился 4 пункт напоить коня. То есть наше приложение отработало правильно? Ну вот мы сейчас в этом убедились и это мы сделали без браузера. То есть мы это делали в памяти компьютера, на котором запускаются тесты.
463: Вот, и теперь смотрите, мы убедились в корректности работы нашего приложения. Давайте теперь напишем проверку, ну, в нашем тесте секцию, которая будет проверять эту, что приложение работает корректно, чтобы мы могли запускать наш тест сколько угодно раз.
464: Без участия человека он нам говорил правильно все работает или нет.
465: Смотрите, я использовал data test id ой, гет бай тест айди для того, чтобы получить наш список, давайте его.
466: Тоже пометим этим атрибутом.
467: Лист. Дальше я использовал ещё 1 функцию из библиотеки реакт тестинг лайбрери визин это функция, которая говорит нам, что искать. Ну, я её использую для поиска элементов.
468: Но я говорю, что нужно искать не глобально, а именно внутри этого листа. Вот. И мы ищем. То есть мы проверяем, что мы можем добавлять элементы в туду лист. Для этого мы заполняем
469: Значение кликаем по кнопке. Нам надо проверить теперь, что в списке элементов отрисовался наш элемент с нашим значением. Вот для того, чтоб для этого мы находим все элементы и проверяем их текст.
470: Для того чтобы найти элементы, нам нужно тоже пометить их, ну, каким-то признаком, по которым мы будем
471: По которому мы будем их искать. Вот и
472: То есть у нас в переменной айтемс получается список найденных дом элементов, которые мы нашли с помощью вот этих хелперов. Дальше мы преобразуем каждый из этих элементов в его текст и дальше вот набор.
473: Вот этих текстов это результат нашего тестового сценария. Мы передаём его в функцию экспект и проверяем, что он содержит текст, который мы добавили через инпут. Вот мы видим, что нас наш тест прошёл, если мы, допустим, закомментируем
474: Вот мы закомментируем код, который диспачи в redux экшн. Ну, при клике на кнопку то мы видим, что наш тест упал, потому что вот мы ожидали, у нас вот такой список.
475: Дел. И мы ожидали, что в нём будет пункт напоить коня, а в нём такого не оказалось. Поэтому наш тест упал. Если раскомментируем, то вот все перезапустилось и тест пройдёт. Вот ещё 1 момент, который хотел показать это
476: Вот мы сейчас научились работать с дом элементами, то есть мы там умеем теперь кликать. Ну, вообще, мы умеем рендерить это в памяти, смотреть разметку, умеем кликать по кнопкам, вводить текст там в поля ввода, но есть
477: Ещё 1 момент, с которым, который мы ещё не попробовали, это как работать с роутингом. То есть вот с этими переходами по страничке, допустим, мы хотим протестировать, что если у нас Урол вот такой слэш эбаут, то
478: У нас открывается страница эбаут. Как нам это сделать? Давайте добавлю ещё 1 тест.
479: Я копирую в него вот Ровно все тоже самое, что у меня есть в предыдущем тесте. То есть вот мы создали тоже star ну то есть это код, который создаёт нашу сущность, экземпляр сущности, который мы будем тестировать. Вот я
480: Ну, вызвал функцию нит стор, потом создал аппликейшн. Ну, наверное, мы можем вот это тоже все скопировать. Вот вопрос, как нам указать нашему приложению на
481: Какой странице оно находится? Вот. И тут смотрите, мы для того, чтобы управлять адресом, ну и вообще переходом по адресам в нашем приложении используем реакт роутер. Вот мы импортируем браузер роутер и
482: Оборачиваем в него наше приложение в общем это тоже получается, что внешняя зависимость, то есть browser роутер это обёртка над history апи, которая есть у браузера и нам нужно как-то место в этот роутер подставить какие-то
483: Заглушечные данные. В общем, если вы посмотрите документацию по react роутеру, вы увидите, что там есть базовый класс, роутер.
484: Вот, и браузер роутер является как бы обёрткой над этим базовым классом class роутер. Вот если мы будем вместо браузера роутера использовать его принимает обязательный параметр хистори. Вот.
485: Сейчас наш так скрипт ругается, потому что мы этот параметр не передали. Хистори это экземпляр. В общем, есть библиотека, которая так и называется history. И эта библиотека является как бы обёрткой над как раз
486: Браузерным хистори апи, давайте её импортируем.
487: From history она уже подключена в нашем приложении, потому что она необходима для работы react роутера. Вот. И давайте посмотрим, что у неё там есть. Вот тут есть функция create браузер хистори. Вот видите её, да?
488: Есть функция create хэш хистори, это когда вы храните путь вашего приложения. Ну вот у урла есть несколько секций, есть хост, есть путь, есть параметры, а есть хэш, то, что после решётки. И вот когда вы
489: Информацию о том, где вы сейчас находитесь, храните после решётки. То есть та часть, которая не вызывает перезагрузку страницы без изменения. Вот вы можете таким образом построить навигацию в своём приложении. И для этого вот вам нужна вот эта функция к хэш хистори. Вот
490: И тут есть, смотрите, крейт мемори хистори. Это очень похоже на то, что нам нужно. То есть это какая-то типа история браузера в памяти. Давайте создадим экземпляр этой memory history. Смотри.
491: Тут я передаю, ну я вызываю эту функцию хистори, передаю туда 2 параметра. Инишиал энтрис это набор Урлов, которые сейчас есть в вашей истории браузера. То есть, если вы вот сюда сейчас, секунду.
492: Вот сюда нажимаете долго. Вот тут есть набор страниц, по которым вы ходили и как раз с помощью вот этого параметра вы можете его задать. 2 параметр. Это initial индекс это номер того элемента на котором мы нахо
493: Находимся прямо сейчас. У нас в массиве типа, всего 1 адрес, вот эбаут, и мы на нём сейчас находимся. Поэтому тут указан 0. Вот дальше этот history вы передаёте в роутер, он больше не
494: Что не ругается, и давайте посмотрим теперь, что у нас отрендерилось для этого, я добавлю сюда.
495: Screen lock to testing плейграунд Турал.
496: Вот тест перезапустился. Смотрите, мы открываем нашу вёрстку и видим, что мы находимся на странице about. То есть мы использовали функцию create memory history. Для того, чтобы создать заглушку. Мы у
497: React роутера уже есть точка расширения. Это у вот этого базового роутера параметр хистори, в которую можно передать заглушку мы передали туда нашу вот эту мемори хистори, которая содержит подготовленные нами данные, и у нас отрендерилась правильная страничка.
498: Вот, давайте ещё, ну, последний примерчик, который сейчас сделаем, мы попробуем кликнуть по ссылке и проверить, что правильно произошёл переход. То есть вот наше приложение вот мы кликаем по вот этим ссылкам.
499: И у нас происходит переход без перезагрузки страницы давайте проверим это в тесте у нас есть cat by test id давайте пометим ссылку по которой хотим кликать тоже атрибутом вот у нас есть линк хо.
500: Который ведёт на адрес просто косая черта.
501: Линк хоум.
502: Дальше мы такие говорим эвенс клик по элементу, который имеет тест айди линк хоум. Все переза.
503: Пустилась. Давайте посмотрим, что на выходе. Вот мы видим, что мы находимся на странице с туду листом и видим, что вот наш дата тест айди есть в нашей ссылке. Вот
504: Наверное, по вот этому демо это все, ну, то есть, ну понятно. Дальше нужно написать эксперт, который проверяет в зависимости от нашего сценария. Ну, в общем, что-то проверяет, что позволяет убедиться, что сценарий отработал. Правильно. Вот давайте, если у вас
505: Есть по вот этой части про react приложения, какие-то вопросы, то, в общем, я на них отвечу.
506: Во классный вопрос, попадёт ли атрибут data test id в продакшн бандл да попадёт, ну точнее, если вы напишите какой-то код, который каким-то образом определяет продакшн бан.
507: Или нет, и типа, либо добавляет аттрибут, либо нет, то, соответственно, ваш продакшн бандл может быть и без этого атрибута. Ну это, в принципе, не сложно сделать, например, на этапе сборки каким-нибудь плагином для вебпака его, ну, либо добавлять, либо выпиливать. Вот.
508: Но мы, например, в своих проектах решили, что от того, что он попадёт, ничего, ну, никакой пользы, ну, точнее, от того, что он попадёт, мы не получим никакого вреда, и мы можем просто
509: Сэконом. Ну, не тратить время на то, чтобы это выпиливать. И типа в наших проектах. Ну, этот атрибут приезжает в вёрстку там вместе с остальными.
510: Вот надеюсь, что ответил на вопрос. Дальше тесты пишутся, когда знаешь, что проверять, есть ли смысл писать тесты, если могут возникнуть непредвиденные ошибки, все ошибки, о которых я
511: Знаю, я стараюсь обработать в основном коде. Кажется, что тут имеются ввиду ошибки, ошибки, которые, ну, какие-то непредвиденные ситуации, возникающие при действиях.
512: Пользователя. И если вы это обрабатываете в основном коде, то это часть вашей бизнес логики. Например, если пользователь регистрируется на сайте и он не ввёл логин, то это некорректная ситуация.
513: Пользователя нельзя зарегистрировать, и ваша бизнес логика будет написана так, чтобы показать пользователю сообщение об ошибке. Вот показ пользователю сообщения об ошибке при его некорректных действиях не является ошибкой вашей программы. Это запланированная работа вашей программы.
514: Ошибка вашей программы будет, например, если вы не показа, если ему нужно показать сообщение об ошибке, а вы его не показали, или если он заполнил все корректно, а, ну, запрос на сервер не ушёл, и то есть
515: Тесты нужно писать на на вашу логику, которую вы пишите в вашей программе, так, чтобы отловить её ошибки. Вот откуда берутся тестовые, ну, типа информация о том, как писать тесты.
516: Ну, из требований к вашему приложению. То есть вам, когда вам приходит задача на разработку программы, у вас есть там список, что корректно, она, что конкретно она должна делать? Этот список, скорее всего, неполный, потому что тот, кто её ставил,
517: Ну, не продумывал, как бы все до конца и, скорее всего, написал это в каких-то общих чертах. Поэтому, когда разработчики заканчивают разработку, приходит ручной тестировщик и начинает, ну, проходиться по этому списку и
518: Придумывать ещё какие-то мелкие сценарии, которые там не учтены и продолжают это тестировать. В общем, вот ручной тестировщик. После того, как он придумал все эти сценарии, он может их точно также зафиксировать. И вот эти 2 списка
519: Ну, входной список для вашей задачи и список сценариев от тестировщика это та информация, ну, по которой вы потом можете писать тесты. То есть ваша программа, когда вы пишите программу, она работает корректно, вы пишите
520: Тесты, которые зафиксируют это, которые проверяют, что она, ну, сейчас работает корректно. И в дальнейшем, когда вы вносите в вашу программу изменения, вы запускаете эти тесты и проверяете, что она по прежнему работает корректно.
521: Идём дальше нельзя ли тестировать роутинг с использования только react роутер дом.
522: Не совсем понял вопрос. Возможно, автор имел ввиду, что можно ли тестировать роутинг. Ну типа, действительно ли необходимо рендерить все ваше приложение для того, чтобы протестировать
523: Роутинг если вопрос был в этом, то ответ в том, что, ну, реактор роутер дом вам не нужно тестировать его протестировали его разработчики в том, что, ну, то есть реактор роутер дом предоставляет вам какой-то api для управления роутингом и его разработчики протести.
524: И что этот api работает корректно. Когда вы используете, используете реакт роутер дом в своём проекте, вы пишите свой дополнительный код, который использует этот апи. И вам нужно вот когда вы тестируете роутинг, вам нужно протестировать свой дополнительный
525: Вот, поэтому, ну, то есть вам, вам нужны тесты на дополнительный код, который вы пишите в вашем приложении. Теперь вопрос, нужно ли для этого рендерить все приложение? Вспоминаем вот то, что мы говорили в начале лекции, что
526: Тестируемая сущность это, ну это такой модуль, который целиком содержит ваш сценарий. Если у вас есть в приложении модуль, который целиком отвечает за роутинг, то в принципе вы можете протестировать только
527: Его, не рендеря всю страницу на, ну, в нашем тестовом приложении нужно было рендерить всю страницу, потому что часть логики про роутит это ссылки, которые отрендерены в шапке. И, ну, то есть мы, если мы их не отрендерим, то мы не сможем
528: По ним кликнуть и ну то есть, если в ссылке будет, допустим, написан неправильный url, то мы протестируем, что роутинг работает правильно, но типа, когда пользователь кликает по ссылке, мы об этой ошибке не узнаем. То есть всегда нужно смотреть
529: Какой модуль целиком содержит ваш сценарий?
530: Идём дальше.
531: Можно ли увидеть в testing плейграунд выполнение действий пошагово нескольких последовательных состояний? Кажется, что нельзя. Кажется, что-то, что показывается в testing плэйграунде, это просто результат. Ну то есть
532: Оно передаётся вот в этом параметре и соответственно, у каждого вот такого урла, когда вы переходите в testing плейграунд, ну, 1 значение этого параметра, значит он отображает 1 состояние, но хорошая
533: Новость в том, что есть ещё другие способы отладки Тестов. Допустим, вы можете, вы можете использовать, ну, запустить ноду в режиме отладки, передать туда, там, давайте
534: Давайте я помогу вам погуглить.
535: Вот я открываю просто документацию по ноджс, и тут написано, когда вы запускаете приложение, но jazz укажите вот такой флаг инспект, и после этого вы можете подключиться отладчиком. То есть, когда у ноды есть flood.
536: Inspect. Когда приложение нож запущено с этим флагом, она, ну, надо начинает слать отладочную информацию на какой-то порт. Ну там есть порт по умолчанию, но вы можете его настроить, ну, порт вашего компьютера, и вы можете потом написать вот так.
537: Ну в каком-то браузере на основе хрома.
538: Браузер инспект. У вас вот тут будет отображаться список всех портов, на которые кто-то шлёт отладочную информацию. Вы можете сюда нажать мышкой и а и в общем, у вас откроется девтулс.
539: Вашего браузера, в котором будет отображаться код ваших Тестов, ну, того, что выполняется в но джс и вы можете его отлаживать типа, смотреть там через watch, значение переменных и так далее. В общем,
540: Инструкцию. Ну как найти инструкцию? Вы теперь знаете, вот это очень легко. Ну, мы этим часто пользуемся на работе.
541: Давайте так, следующий вопрос. Библиотека тестинг лайбрери очень похожа на selenium, и в плане работы с 2 элементами получается, селениум не нужен. Можно проводить функциональное тестиро?
542: Тут, ну, если очень как бы сильно абстрагироваться, то да, Ровно для этого я вам рассказываю эту лекцию, чтобы вы могли тестиро.
543: Функциональность вашего продукта при помощи модульных Тестов это дёшево, ну то есть это работает сильно быстрее, чем селениум. Если кто не знает selenium это такая обёртка над браузером, которая позволяет
544: И, ну, писать код, управляющий браузером. То есть вы можете при помощи селениума поднять, допустим, хром, открыть в нём страничку, кликать точно также по кнопкам и так далее. И вы можете при помощи селениума писать тесты, которые открывают ваш настоящий интерфейс.
545: Кликают по кнопкам и смотрят, как бы что отрендерено на страничке в общем, вот эта библиотека react клайбер позволяет делать примерно тоже самое, только не открывая реальный браузер, а делая это все в памяти.
546: Это часто срабатывает, и если вы можете протестировать что-то в памяти, не поднимая реальный браузер и не ходя в него по сети, то лучше тестируйте в памяти, но на самом деле вы не все можете протестировать в памяти про это, там будет в другой лекции.
547: Так.
548: На, например, вы не можете протестировать в памяти вёрстку, ну, стиле. Вот за то, чтобы отрисовать на экране пиксели, отвечает движок в браузере, который обрабатывает ваш цсс. И вот в этих тестах, которые мы пишем.
549: Вы такое проверить не сможете. Допустим, вы не можете в этих тестах проверить вёрстку при помощи сравнения скриншотов. Если в вашей вёрстке будет баг, вы об этом не узнаете.
550: Так, вроде это все вопросы. Так, это была последняя, последняя демонстрация кода. Сейчас осталась такая абстрактная часть, как писать? Ну что, что нужно писать?
551: В тестах так, чтобы они приносили пользу, а не вред, вот и возвращаюсь обратно в презентацию.
552: Так, ну в общем, как писать полезные тесты? У Тестов есть 3 характеристики, от которых зависит их польза. 1, это надёжность.
553: 2 это лёгкость поддержки, и 3 это понятность, что такое надёжность, надёжность, это качество Тестов, которое говорит, можете ли вы доверять их результатам, в каком случае вы можете не доверять?
554: Результатом. 1 вариант. Если у вас на какие-то важные сценарии не написаны тесты, то есть у вас написан какой-то код, у вас какая-то пачка Тестов, вы их такие запустили, они зелёные, но на какие-то важные сценарии тесты не написаны, поэтому вы не
555: Знаете, сломались они или нет. И в этом случае вы, ну, если вы это обнаруживаете, вы тестам не доверяете. Вот 2 вариант, когда вы можете не доверять тестам, если они выдают вам ложные результаты. То есть, если у вас код сломался, а тесты зелёные, то
556: Вы перестаёте им доверять, если, наоборот, тесты упали. Ну, например, если вы не изолировали внешнюю зависимость, и она выдаёт вам непредсказуемые данные, и тесты у вас падают, хотя код работает правильно? Вы тоже перестаёте им доверять. То есть вот
557: 2 причины. Важно, чтобы было доверие к тестам и что для нужно сделать, чтобы доверие было. Во первых, нужно следить за покрытиев за покрытием сценариев тестами следи.
558: Это не значит, что сделать какое-то действие. Вот типа я пришёл и слежу. Это значит, что у вас должен быть в команде какой-то процесс, при котором, ну процесс это правило того, как, какие действия должны делать люди, это как программа для людей у вас должен
559: Быть процесс, при котором регулярно делаются какие-то действия, которые актуализируют список тестовых сценариев, причём важно, ну как бы важно, чтобы сценарии были покрыты тестами, но
560: Они могут быть частично не покрыты. Например, если вы разработали функциональность, но ещё не успели написать тесты. Но у вас должны быть хотя бы где-то зафиксированы эти сценарии. У вас должен быть какой-то каталог сценариев, чтобы вы хотя бы понимали, как должно вести себя ваше приложение. Вот, и
561: И в яндексе, например, есть для этой цели вот такой сервис теспарто тестовых сценариев. То есть, когда разработчики делают задачу, у них есть требования, они сделали задачу
562: Они вот эти сценарии, которые написаны в их требованиях и которые потом придумал ручной тестировщик, записывают в эту базу. И потом по ней можно строить всякие метрики и видеть картину сколько тест.
563: Покрыто вашими сценариями, сколько? Нет? Вот тут есть ещё 1 момент. Есть такой подход, ну такой термин код каверидж, то есть покрытие кода тестами, когда вы запускаете тест
564: На вашем коде и специальная штука считает, какое количество, ну, какие места в вашем коде были вызваны во время Тестов, а какие не были. Вот, и некоторые люди считают, ну, как бы фиксируют это, считают количество процентов и
565: Тоже там строят какие-то графички и используют их для того, чтобы оценить покрыто. Ну типа, все ли у них хорошо с покрытием, тестами. Вот код каверидж это совсем другая штука, она даёт вам другую информацию, она вам может показать, какие ме,
566: У вас точно ни разу не вызывались в тест в тестах и то есть какие места у вас точно не покрыты, она у вас говорит, какие места покрыты плохо, но она не говорит вам, что у вас хорошо. То есть, если у вас стопроцентный код каверидж, это не значит, что
567: У вас в тестах проверки, которые действительно проверяют корректность ваших сценариев. Это значит просто, что каждое место вашего кода хотя бы 1 раз каким-то образом отрабатывало в тесте, в каком-то тесте. Ну не факт, что корректно вот
568: То есть это важное отличие. Надо смотреть именно каверидж сценариев, а не каверидж строк кода и каверидж строк кода. Как раз вы можете посчитать автоматически, но это бесполе. Эта информация вам не очень полезна, а каверидж сценариев вы можете посчитать только если
569: Организуете процесс, при котором у вас постоянно актуальный каталог сценариев. Идём дальше. То есть вот мы говорили про надёжность, говорили, что там 1 случай, когда тесты ненадёжны, когда они не на
570: 2 случай, когда тесты ненадёжны, когда они выдают ложный результат и в каких случаях тесты могут выдавать ложный результат. Ну, если там написаны проверки, не дающие вам информацию о результате, например,
571: Вот этот слайд это прям реальный кусок кода 1 из предыдущих школ, разработки интерфейсов и ну то есть это, это типа кусок чьей то домашки и тут проверяется функция, формат date. Ну.
572: Название. Похоже, что она проверяет, как форматируется дата в строку. И на эту функцию написано 2 теста. 1 тест проверяет, что функция должна возвращать строку, a2 тест проверяет, что если передать левое значение, то вернётся пустая строка. Вопрос, если
573: Мы вот из функции формат date, удаляем все содержимое и пишем ретурн пустая строка, то пройдёт ли 1 тест, да, пройдёт потому что пустая строка это строка пройдёт ли 2 тест? Да пройдёт потому что если
574: Передать фигню, то тоже получим пустую строку как и обычно, 3 вопрос какой будет code coverage? Ну, очевидно, что все содержимое функции, формат date выполнялось во время Тестов, значит, код каверидж будет 100%.
575: Работает ли сценарий? Очевидно, нет, не работает. В общем, проверки должны быть должны зависеть от таких качеств результата, которые, ну, по которым можно сказать, что действительно продуктовый сценарий.
576: Отработал корректно. Вот, вот это супер важно. Надо писать в тестах обязательно проверки, связанные с продуктовым сценарием, который вы проверяете дальше. Как ещё
577: Ну, можно получить ненадёжные тесты, если вы делаете в тестах ошибки, то вот вы сразу перестаёте им доверять. Это такой субъективный как бы, момент, потому что, ну,
578: Тесты это, ну они воспринимаются как инструмент, который страхует вас от ошибок. И если вы видите, что в вашем инструменте в самом есть ошибки, то вы как бы перестаёте сразу на них смотреть, перестаёте сразу писать тесты. Вот, и мы
579: На самом деле про это говорили уже несколько раз в лекции во первых, когда вы пишите тест, обязательно пойдите в код, сломайте этот код, ну сделайте там умышленную ошибку и проверьте что test её отловил, то есть тест это такой же код, его надо тестировать, его задача
580: Ошибки, поэтому вам обязательно надо проверить, что он не только что он корректно проходит, когда нет ошибок, но и что он корректно падает. Когда ошибка есть. Дальше не добавляйте логику в тесты. Логика это условия, циклы, то есть это
581: Такие конструкции, в которых выполнение теста может пойти по разным веткам. Если вы пишите логику в тестах, это значит, что она смотрит на какие-то данные и при разных данных выполнение может пойти по разному. Это значит, что у вас тест, ну,
582: Разные запуски теста будут выполняться в разных условиях и в них будут происходить разные действия. И это значит, что у вас в каких-то случаях не будут, ну в каких-то случаях будет выполняться 1 часть проверок.
583: В каких-то случаях будет выполняться другая часть проверок и значит, что вы можете в этом месте легко пропустить баг и сделать ошибку. В общем, если вы хотите написать if внутри теста, значит ваш тест нужно разделить на 2, который проверяет 1 ветку.
584: И и проверяет 2 ветку ифа, это значит, что у вас 2 разных сценария.
585: Дальше изолируйте тесты от внешних зависимостей. Про это мы говорили. Ну то есть тут супер важно, чтобы все тесты выполнялись в одинаковых условиях и чтобы в них были предсказуемые данные. Поэтому
586: Обязательно. Ну, смотрите, какие есть внешние зависимости, и заменяйте их на заглушки. И ещё 1 важный момент тесты нужно изолировать не только от внешних зависимостей, но и друг от друга. Это значит, что тест
587: Не долж. Ну, разные тесты не должны иметь общего состояния. Предположим, вы сделали глобальную переменную, в которую положили такой большой объект с тестовыми данными, и во всех тестах её используете. К чему это может привести, если ваш, у вас
588: Какой-то тест отработал некорректно и каким-то образом поменял содержимое этой переменной, то это содержимое некорректное попадёт во все остальные тесты, для которых оно будет неожиданным, и они могут отработать не так, как
589: Задумывалось изначально, потому что у них некорректные входные данные, и это значит, что ваш код не менялся, он работает по прежнему правильно, а тесты упадут в этом случае из за того, что на них повлиял какой-то соседний тест. Вот, поэтому не
590: Используйте общее состояние для разных Тестов всегда. Ну, если у вас в нескольких тестах нужно одинаковое состояние, сделайте функцию, которая его создаёт, и несколько раз вызовите её, чтобы у вас создалось несколько разных экземпляров этого состояния.
591: И у каждого теста был свой экземпляр. Вот это супер важно. То есть по коду это кажется, что без разницы, но это когда у вас 1000 Тестов на проекте, то вам если выполняете эти рекомендации, вам становится сильно
592: Проще с ними работать.
593: Мы проговорили, ну, типа про надёжность. Там на самом деле ещё можно много пунктов накидать, но вот это прям частые места, в которых могут быть проблемы. Вот теперь про лёгкость сопровождения, лёгкость, сопровождение, это мера. Показываю.
594: Сколько усилий вы тратите на то, чтобы адаптировать ваши тесты к изменениям вашего кода. Допустим, если вы переместили кнопку в другое место, ну, кнопку добавить вам нужно. Ну, если у вас там, если вы её искали,
595: Искали через data test id, то скорее всего, у вас в тесте ничего не поменяется если вы искали её там по тексту, например и переименовали текст, то вам нужно пойти в тест и поправить текст, по которому вы ищете вот это те затраты, которые вы.
596: Делаете при, ну, для адаптации Тестов, при изменении вашего кода. Вот, и какие тут есть правила. Важное правило. Тестируйте интерфейс, а не детали реализации, если вы будете
597: Тестировать какие-то кишки вашего приложения, а не то, ну от чего действительно зависит выполнение вашего сценария. Ну не то, с чем, не знаю, не то, что видит пользователь, грубо говоря, то это значит, что
598: Во первых, у вас могут быть какие-то не протестированы, ну какая-то не протестированная логика, которая не попала в ваши тесты, потому что вы тестируете как бы более глубокий слой. Это опять в тему. Можно ли тестировать роутинг, не рендеря?
599: Приложение. Вот, во вторых, ваши тесты начинают вам мешать, когда вы правите какие-то внутренности вашего приложения и ну что делаете? Какой-то рефакторинг и ваш работа вашего приложения при этом не меняется, то вам
600: Нужно будет вместе с этим рефакторингом ееще рефакторить ваши тесты. Если вы смотрите только на какой-то интерфейс, то вы меняете внутренности. Интерфейс остаётся таким же, и тесты как раз в этом месте помогают вам понять, что ваш рефакторинг ничего не сломал. Вот.
601: Не тестируйте кишки вашего приложения. Ещё 1 момент. Не дублируйте проверки, часто сценарий. Ну вот мы говорили в начале, что сценарий предполагает какое-то большое количество действий пользователя. Например, если сценарий это сохране,
602: Вот пользователь регистрируется на сайте, и он вводит какие-то данные, нажимает кнопку сохранить, то в этом тесте будет большое количество действий, открыть форму, ввести там 10 полей, нажать кнопку, сохранить. Вот, и может возникнуть желание покрыть
603: Этот тест проверками, ну типа проверить, что там ввелось каждое поле. В общем, сделать много проверок, которые дают полностью информацию об этом сценарии. Теперь у вас, предположим, другой сценарий, когда пользователь заполняет
604: 1 из полей неверно и нажимает кнопку сохранить. Получает сообщение об ошибке. В этом случае вы будете делать тоже самое. Те же самые действия заполнять те же самые 10 полей. Будет отличаться 1 поле, которое вы заполнили неверно. И если вы
605: Будете вот писать в тестах много проверок, то ваши проверки в тестах будут пересекаться, и это значит, что если сломается какое-то 1 конкретное поле, то у вас упадут сразу все тесты, в которых были на
606: Проверки на него старайтесь в каждом тесте, вот именно саму проверку, которая определяет, прошёл тест или нет, завязывать только на ту информацию, которая связана со сценарием, вот который вы проверяете.
607: То есть, если вы делаете много действий, а проверяете, ну, вам важно только 1, то проверяйте только это 1 действие, а на остальные действия лучше напишите отдельные тесты. Если там будет дублироваться код, вынесите его в общий хелпер, как-то так. Вот, и
608: Ещё 1 момент. Такое понятие, как избыточное специфицирование, это когда вы пишите проверку, которая более строгая, чем нужна вам для того, чтобы убедиться в корректности работы вашего сценария.
609: Пример. Ну опять наш тудулист, у него есть какие-то элементы айтим 1 айтим 2. Мы добавляем айтим 3 и нам нужно проверить, что он корректно добавился. У нас результат добавления это поле айтим, мы его сравниваем.
610: Вот таким массивом, а этим 1, а этим 2, tim 3 вот, предположим, в нашем туду листе поменялась логика, и элемент добавляется, стал добавляться не в конец, а в начало у нас добавление будет продолжать рабо.
611: Работать корректно, но вот этот, ну, получившийся массив Айтимов будет другим, потому что новый элемент будет с другой стороны, и наш тест упадёт, хотя добавление как бы не сломалось, оно по прежнему работает корректно.
612: Что тут можно было сделать? Вы могли бы использовать вместо сравнения полностью всего массива функцию ту контейн, которая проверяет, что в массиве есть заданный элемент. В этом случае тест будет
613: Более гибким, он не будет ломаться от того, что поменялась какая-то соседняя логика. То есть вы проверяете, что, ну вы ваши действия, которые вы проверяете, что-то добавляем и результат, который вы проверяете, что-то, что вы добавляете, там появилось
614: В общем, если вы будете писать в тестах проверки с учётом этого, то это, ну, ваши тесты будут более поддерживаемыми, и это сэкономит вам время. Ну, вам нужно будет делать меньше действий на то, чтобы адаптировать ваши тесты при
615: И изменениях в коде. Так мы поговорили про надёжность, про лёгкость поддержки и последний пункт, лёгкость понимания Тестов. Это 3 пункт. Ну вообще вот эти 3 пункта надёжность, лёгкость поддержки.
616: Лёгкость понимания это прям ключевые характеристики Тестов. Если вы 1 из них роняете, то вам становится очень тяжело работать с тестами и вам становится проще их там не писать. Ну и вы получаете как бы все минусы, связанные с этим.
617: Ну, это примерно как вот перетестировать. Для того, чтобы перетестировать вручную, надо, типа, посадить тестировщика на 3 месяца и там 3 месяца платить ему зарплату. Вот это неприемлемо. Если вы просадите 1 из этих пунктов, это тоже будет, ну, неприемлемо. Вот.
618: И когда вы работаете с вашим проектом, ну, есть статистика, что программисты 80% времени читают код, и там 20% времени пишут какой-то новый код. В общем, очень важно, чтобы, ну, чтобы код Тестов тоже был.
619: Читаемый код Тестов это такой же код, как код проекта и с ним будут работать люди. Вот в общем, что тут можно сделать, чтобы код теста был читаемым и
620: Их результат тоже был понятным. В общем, во первых, давайте тестом осмысленные названия. Если у вас русскоговорящая команда, то пишите название на русском языке. У меня есть тоже примеры из предыдущих шри. Это вот реальная работа.
621: Какого-то студента надо было протестировать модуль, и он написал тесты номер 1 номер 2 номер 3. Вопрос, если у вас тест упал и вы видите отчёт, у вас упал тест номер 12. Ну типа, че вы будете с этим делать? Ну?
622: Как бы, видя этот отчёт, вы ничего не сможете с этим делать. Вам надо будет только идти в код и копать. А что же это за тест номер 2? Ну типа, прям читать его код, понимать, че он делает. В общем, это сложно. Ещё вариант тут, тут тоже абсолютно реально.
623: Ну, в смысле, из домашки студентов тут написаны в качестве названия Тестов, названия команд, которые он проверяет. Но, опять же, если, допустим, какая-то вот у нас есть сущность, у неё есть несколько команд, мы по
624: Что какая-то команда работает неправильно, но как именно неправильно она работает. Типа, а точно ли это непра? Ну вообще никакой информации нет. Просто мы знаем, что что-то сломалось. В общем, так себе. Рекомендую.
625: Использовать для названия вот такой шаблон. В общем, обязательно в названии указывайте ответы на вот эти 3 вопроса, которые мы разбирали в начале. Скажите, в каком контексте происхо. Ну вы что-то тестируете? Какой
626: Сценарий вы тестируете. И какой результат вы ожидаете на выходе из этого сценария? Ну вот, например, если кликнуть в корзину, блок будет удалён. Тут, если выполняется, ну, если вы находитесь в каком-то контексте, кликнули на кор.
627: То блок будет удалён. Это результат вашего сценария. Вот называйте всегда тесты по этому шаблону. Не обязательно прям, чтобы была такая фраза, ну, в такой форме. Но главное, чтобы была отражена вот эта вот информация, вот эти 3 ответа на 3 вопроса, это
628: Вам очень сильно поможет и ориентироваться в коде. То есть, когда вы читаете тест, вы посмотрите название, и вы будете сразу понимать, какую логику он проверяет, и вам будет проще в нём разобраться. И эта информация. Если вы видите её в отчёте о сломавшихся тестах, то она
629: Очень поможет вам сразу понять, в какую сторону нужно копать, чтобы починить ваше приложение.
630: Дальше. Кроме того, что вы можете давать тестом осмысленное название, вы ещё можете делать более осмысленные проверки, и если вы будете использовать более подходящий апи для проверок, то вам
631: Будет точно также проще по коду понять, что они делают, и вы сможете в отчёте о тестах увидеть больше информации, которая, ну, на основе которой будете принимать какие-то решения.
632: Вот в этом примере мы проверяем, что, ну, опять тот же самый пример. Проверяем добавление элементов. Тудулист. Что мы, что мы тут делаем? Мы берём поле, items, проверяем, что
633: Какой-то из Айтимов имеет название айтим 3 и сохраняем этот результат true или false в переменную result, а дальше мы проверяем, что result равно true если этот тест упадёт, что мы увидим в отчёте, мы увидим, что false не равно true вот если мы
634: Пользуемся вот этим api, который предоставляет жесты для проверки элементов массивов, то есть функция то контейн, ну, мы её использовали как раз в примерах, то мы в отчёте увидим, какой элемент мы ищем, какое у нас текущее содержимое массива.
635: То есть это даст нам сразу больше информации. Нам даже не нужно будет идти в код и не нужно будет запускать отладчик, чтобы понять, что там произошло. Вот, вот эта вот ссылка, ну опять будет прикреплена презентация к лекции, вы можете её скачат.
636: И там потыкать по ней или можете в гугле это набрать или в яндексе. В общем это ссылка на документацию какой есть апи у джеста для выполнения различных проверок именно не общих.
637: Когда там true nee равно false, а именно каких-то специфических проверок, которые подходят для какой-то конкретной ситуации и дают о ней больше информации, вот, кроме того, вы можете писать собственные проверки, ну, типа добавлять расширения, которые добавляют бюджет.
638: Собственные проверки, какие-то нужные конкретно ваши задачи. Вот. И следующие 2 пункта идут вместе, потому что они связаны друг с другом. Во первых, отделяйте проверки от действий. То есть помните мы
639: Писали тест, который состоит из 3 частей. Там была подготовка, проверяемое действие и проверка условия. Чтобы понять, прошёл тест или нет. Всегда разделяйте эти 3 пункта. Вот и смежный пункт. Используйте осмысленные названия переменных в тестах.
640: Смотрите, вот этот тест выполняет корректную проверку, то есть он проверяет функцию get пёс бай тайп и проверяет, что она типа на заданные входные параметры выдаёт ожидаемый
641: Результат. Вот, но вот такой тест читать очень тяжело, потому что тут много операций написано в 1 строчку и непонятно, где границы между, ну где заканчивается 1, начинается другая, и просто эта строчка длинная, её
642: Тяжело читать этот тест можно переписать вот так. То есть мы разделили эту строчку на несколько. Мы написали больше кода, но за счёт этого тест стал более понятный. Во первых, мы разделили 3 части. Подготовка действия и проверка, как мы это делали в наших примерах.
643: Во вторых, мы вот эти промежуточные результаты, которые мы получаем в этих частях, присвоили в промежуточные переменные, и мы дали этим переменным какие-то осмысленные названия. Вот название переменных это дополнительная инфор.
644: Информация, которая, из за которой вам будет проще понять, что написано в тесте. Поэтому, в общем, относитесь к этому серьёзно. Если ваши тесты будут нечитаемые, вы не сможете с ними работать. Если у вас будет там 2000 нечитаемых Тестов, вы
645: И вам придётся их выкинуть.
646: Вот, и ещё 1 очень важный пункт. Старайтесь, чтобы в тестах была только та, ну, был только тот код, который важен для вашего тестового сценария. Весь рутинный код прячьте в хелперы.
647: Пример. Вот, предположим, ваш блок зависит от, ну, типа ваш реакт компонент, который вы тестируете на вход, должен получать объект с большим количеством полей, и чтобы его отрендерить, вам нужно, ну, указать все значения.
648: Этих полей. При этом вам нужно для конкретного теста, там значение какого-то 1 из полей. Остальные не так важны. В общем, как это можно написать. Вы делаете вот такой helper и делаете там, ну возвращаете из него
649: Объект, который содержит значение по умолчанию. Также в этот хелпер в качестве входного параметра можно передать объект, у которого заполнены часть полей. Это те поля, которые важны для вашего теста. И вы в конце просто вот тут в пример через спред оператор
650: Вы просто до определяете дефолтные значения теми значениями, которые вы передали как входной параметр. Вот это эта функция типа при каждом вызове будет создавать новый объект и добавлять в него
651: Какой-то набор значений, важных для вашего теста тогда, если, допустим, в вашем тесте важен, ну тут пример для пользователя. Вот пример теста, в котором важен возраст пользователя, вы получаете данные для вашего
652: Компонента просто 1 строчкой, вызвав этот хелпер и передав туда те поля, которые нужно доопределить. Вот
653: Ещё 1 пример как можно упростить тест вынеси, вынося логику в хелперы это вот как раз кастомные проверки, ну, расширения для api джеста, которые позволяет
654: Понять какие-то кастомные проверки, нужные вашей задачи, это, ну там есть документация, как их писать. Это вот пример реальной проверки. Ну как я скопировал из своего проекта, чуть чуть там упростил, чтобы оно влезло на slide. Это функция, которая проверяет
655: Параметры урла. То есть у нас есть много задач, где там рендерятся на странице какие-то ссылки, их url как-то генерируется, и нам надо проверить, что он сгенерирован. Правильно мы, ну написали, ну вместо того, чтобы в каждом
656: Testa там проверять не знаю по регулярному выражению или там как-то парсить этот url и писать там большое количество кодов то есть мы написали вот такое расширение для джеста и дальше мы проверяем ссылки просто
657: 1 строчкой и это, то есть пишем экспект, указываем ссылку, которую хотим проверить, вызываем наше расширение, которое мы написали и говорим там путь с которым сравнить. Вот. В общем, вот такая штука очень сильно увеличив.
658: Читаемость Тестов, потому что весь ваш рутинный код уходит типа в какие-то хелперы, то есть он скрывается как бы под капотом вы видите только суть теста.
659: Вот, и ещё 1 момент. Ну, это из мира селениума тоже пришло, но вот так, как мы пишем, получается функциональные тесты в памяти без браузера. Ну, это функциональные тесты, поэтому он применим
660: К ним тоже. То есть это можно использовать без селениума. Паттерн пейдж. Обжект это такой объект, который является как бы обёрткой над вашим интерфейсом, в котором записаны все там селекторы, все какие-то признаки.
661: По которому вы ищете элементы вашего интерфейса. Ну, для того, чтобы вы не дублировали код, допустим, у вас есть много Тестов, которые там в ходе своих, ну, действий, которые они выполняют, кликают на кнопку добавить элемент.
662: Лист у вас в кнопке написан какой-то test id и если бы вы как бы не задумывались об этом, вы бы просто в этих тестах за ну как мы в примере делали, захардкодили бы этот тест айди и он бы у вас многократно дублировался теперь, если бы
663: По какой-то причине вот этот интерфейс изменился, например, вместо кнопки, там было бы что-то, ну не знаю, какой-то другой элемент или там пришлось бы поменять тест айди. Это значит вам нужно было бы пойти по этим тестам и все.
664: Ну, типа, везде это поменять. Вот во всех тех местах, где у вас это было захардкожено. Вот вы можете вынести, сделать вот такой, например, класс, там, туду, пейдж, обжект, у него есть свойства там input и items, ну и там ещё свойства батон.
665: Если нам кнопка нужна, вот, и в нём захардкожены вот эти селекторы, по которым мы ищем элементы. Соответственно, вы можете во всех местах, где вам нужен тест использовать вот этот, ну, обраща.
666: К интерфейсу через этот объект. То есть вот вы создали этот пейдж и говорите пейдж импут, когда вы обратились к его свойству, импут, у него выполнится вот этот контейнер квали селектор, ну, по заданному классу вот
667: Ваш код будет, ну, ваш код Тестов будет более читаемый. Если вам нужно будет поменять класс у импута, то вы поменяете это, ну, в вёрстке и поменяете в обжекте, и ваши тесты будут работать правильно? Вот, в общем,
668: Это 3 просто примера, они про 1 и тоже, про то, как вынести код из Тестов в какие-то хелперы. И это 3 примера. Прям из разных областей мы вынесли код для подготовки данных, код для обраще.
669: К интерфейсу и код для проверок. А суть этих примеров в 1, что оставляйте? Ну, сейчас ваш тест проверяет какой-то сценарий и оставляйте в коде теста только ту инф.
670: Информацию, которая связана с вашим сценарием, а всю рутинную информацию выносите оттуда, тогда ваш тест будет легко читать, и вам будет легко с ним работать, и вы можете даже вам это может даже нравиться.
671: Блин, очень долго разговариваем. В общем, тут есть ещё последний пункт. Поддержать соответствие между тестами и кодом. Ну, не буду как бы про него подробно рассказывать. Суть в том, что если у вас сломался тест, вы должны легко найти
672: В коде, с которым он связан, и вам нужны какие-то правила, как код Тестов будет соответствовать коду вашего приложения. Например, вы можете делать файлы с одинаковым названием, но там разными суффиксами и по совпадению названий понимать, что с чем связан
673: Вот ещё вариант про группировку, про логическую группировку Тестов через функцию дискрайб дискрайб это ещё 1 функция, которая, ну глобальная функция, которую предоставляет тестовый фреймворк, это и jest, и мокко её предоставляет, в общем, её.
674: Суть в том, что вы можете разбить тесты на группы, и у вас получается такая структура Тестов, в которой вам проще ориентироваться, потому что когда вы видите большой плоский список Тестов, в нём количество сущностей очень большое и вас
675: Ваш мозг как бы плохо это воспринимает. Если вы видите, если у вас все сгруппировано, то вы видите небольшой список групп, ваш мозг легко выбирает нужную, у неё внутри, там ещё небольшой список подгрупп и так далее. Вы можете как бы постепенно погружаться и на каждом уровне как бы
676: Чётко видеть, что там есть вот все, мне кажется, вам было тяжело, но я надеюсь, что интересно в общем резюме, о чем мы вообще
677: Говорили, мы говорили сначала про суть автотестов, про том, что про то, что основная польза от автотестов в автоматизации, то есть в дешёвой проверке, ну, повторной проверки сценариев. И это нужно для того, чтобы убедиться, что при внесении изменений в ваш проек,
678: Он продолжает работать правильно. Дальше мы поговорили. Вот супер важная тема про 3 вопроса, которые необходимо, на которые необходимо ответить в своей голове при написании Тестов. Это какой сценарий?
679: Мы тестируем экземпляр. Какой сущности нам нужно создать для этого и что у нас является результатом этого сценария. Всего 3 варианта результата. Дальше мы поговорили про заглушки. Ну это стаб, это тупые заглушки, которые просто подсовываю
680: В наши тесты те данные, которые они ожидают, ну то есть они вместо непредсказуемой внешней зависимости подсовывают в тесты предсказуемые данные, и мы проговорили про умные заглушки, так называемые моки.
681: При помощи которых можно тестировать взаимодействие вашей сущности. Ну, которую вы проверяете с внешними системами. Моки запоминают, с какими параметрами к ним обращались. И на основе этой информации вы можете, ну, ваш тест может принимать решение, прошёл он или упал. Вот, и
682: Мы в конце поговорили про характеристики ну как писать тесты так, чтобы они приносили пользу и были приемлемыми в своей работе, они должны быть надёжными, сопровождаемыми и понятными, в общем.
683: Это звучит как абстрактные какие-то вещи, но это супер важно и мы прошлись вот по конкретным местам, ну по конкретным примерам этих абстрактных вещей. Все, давайте посмо.
684: Смотри, вопросы, которые прислали.
685: И будем заканчивать.
686: Так, 2 вопроса всего есть. Есть проекты, в которых количество модульных Тестов больше 20000 на 1 часть. Есть ли смысл в таком количестве Тестов, когда
687: Те интеграционные тесты сейчас, все эти, сейчас все эти варианты все равно работают быстро. Ох, много вопросов. Есть ли проекты, в которых модульных Тестов больше 20000 на 1 часть я пока не видел у нас
688: Ну, в наших проектах, проектах, ну, у нас небольшие, в принципе, проекты сейчас, ну, в моей команде, и там количество Тестов, ну, какие-то там сотни, ну, меньше 1000 на проект, именно модульные.
689: А до этого я работал в яндекс директе. Это очень большой проект. Самый большой проект из всего, что я видел, там модульных Тестов не было вообще, но там было 2000 интеграционных Тестов, и они перед релизом гонялись больше 4 часов. Вот.
690: А, ну вот тут, тут есть кусок вопроса про то, что интеграционные те тесты все равно работают очень быстро. Вот это ответ, типа наши там 300 модульных Тестов гоняются 15 секунд.
691: А 2000 интеграционных Тестов директа гоняются больше 4 часов. Вот. Ну, они, конечно, быстрые, но не до такой степени модульные тесты по определению быстрее, потому что они работают как бы в памяти.
692: Там нет запросов по сети селениум. Ну, запрос по сети по сравнению с запросом к памяти. Это как там вот вы сидите на диване, взять булочку со стола или сходить за ней в магазин, если вам надо 2000 раз сходить в магазин.
693: Точно там сильно будет медленнее, чем 2000 раз взять булочку со стола, так про e2e и интеграционные тесты.
694: Блин, наверное, не буду рассказывать, потому что у вас дальше, ну, как минимум, студентов шри, будет ещё кусок лекции, в которых там будет этот вопрос разбираться. Вот. И 2 вопрос. Расскажите про утечки памяти при тестировании. Как их определить?
695: Наверное, ничего особого сказать не могу. То есть ваш тестовый код, который вы пишите, это такой же джаваскрипт код, который вы пишите, допустим, для своего приложения, там могут быть утечки памяти.
696: В наших тестах мы с таких, с такой проблемой не сталкивались. Ну то есть, если то там нужно применять при написании кода те же правила, которые вы применяете для продакшн кода. И как бы тогда все будет хорошо.
697: Так, все, вроде это все вопросы. В общем, спасибо большое, что меня послушали. Я рад, что вы пришли, что вам это интересно. Мои контакты telegram.
698: И почта на слайде. Если у кого-то будут прям какие-то вопросы, кто-то захочет обсудить, то пишите мне, я обязательно всем отвечу вот дальше. Ну сейчас у нас трансляция, насколько я понимаю, будет выключаться.
699: И студенты шри, ну, могут перейти в зум там для дальнейшего обсуждения.