Для будущих учащихся на курсе «JavaScript QA Engineer» и всех интересующихся темой автоматизацией тестирования подготовили перевод полезной статьи.Также приглашаем принять участие в открытом вебинаре на тему «Что нужно знать о JS тестировщику». На занятии участники вместе с экспертом рассмотрят особенности JS, которые нужно держать в голове при написании тестов.  Юнит-тесты — это здорово… когда они надежно работают! На самом деле, есть старая поговорка, что «плохой тест — это хуже, чем вообще никакой тест». Я могу подтвердить, что недели, проведенные в погоне за случайно «ложным отрицательным» тестом, не эффективны. Вместо этого можно было использовать это время для написания рабочего кода, который поможет пользователю. Так что поговорим об одной из этих простейших методик написания менее нестабильных тестов: тестирование фабричных данных. Но прежде чем перейти к тому, что такое фабричные функции и зачем их использовать, давайте сначала попробуем разобраться, какой тип нестабильного теста они устраняют. Аспекты тестов, которых мы хотим избежать Высокое зацепление Отсутствие типобезопасности (что приводит к длительному рефакторингу и ошибкам) Огромные папки фикстур Факторные функции все это исправят. Фабричная функция — это функция, которая создает объект. Вот так просто. Да, существует шаблон «абстрактная фабрика», популяризированный книгой "Gang Of Four's Design Pattern" несколько десятилетий назад. Давайте сделаем функцию красивой и простой. Сделаем функцию, которая упрощает процесс создания, чтобы было легче тестировать. Вот самый простой пример в мире: Посмотрим, как такой простой шаблон может быть использован для исправления аспектов нестабильных тестов, описанных выше. Мы начнем с описания того, как обычно пишутся тесты, а затем будем разрабатывать решение итеративно по мере решения каждой из задач. Все начинается невинно. Представим, вы или другой мотивированный разработчик в команде хотели бы поделиться опытом и добавить юнит-тест для одной из страниц. Для тестирования функции вы сохраняете некоторые тестовые данные в JSON-файле. Cypress (самая удивительная на момент написания этой статьи библиотека для тестирования пользовательского интерфейса), которая даже поощряет вас использовать JSON файл с тестовыми данными. Но проблема в том, что это даже удаленно не типобезопасность. Поэтому у вас может быть опечатка в вашем JSON и вы будете тратить часы на поиски проблемы. Чтобы проиллюстрировать это, давайте рассмотрим пример кода для бизнеса и кода для автоматизации тестирования. Для большинства этих примеров мы предположим, что вы работаете в страховой компании, которая объясняет, как работают правила в каждом штате США. Код выглядит неплохо, так что давайте напишем JSON для хранения положительного тестового примера. А теперь тестовый код. Я продемонстрирую проблему, используя какой-нибудь psuedo-код для теста Cypress, но вы можете представить себе, что это происходит с любым тестовым кодом, в котором вы загружаете фикстуры и запускаете тестовое утверждение. Выглядит неплохо, и он отлично работает, пока вам не понадобится протестировать другой сценарий с участием другого пользователя. Что вы тогда сделаете? Стоит ли просто создать еще один JSON-файл фикстуры? К сожалению, это простое решение возникает постоянно, потому что оно самое простое (поначалу). Но с увеличением количества случаев, растет и количество JSON-файлов. Вам понадобится 52 различных JSON-файла, чтобы протестировать каждую страницу для каждого пользователя в США. Когда вы начнете тестирование, если пользователь является или не является администратором, вам придется создать 104 файла. Это много файлов! Но у вас все равно есть проблема типобезопасности. Допустим, Product Owner приходит в команду и говорит: «Давайте будем отображать имя пользователя, когда мы его приветствуем». Таким образом, вы добавляете свойство name в интерфейс и обновляете пользовательский интерфейс для работы в этом примере. Здорово, что вы обновили код для бизнеса, но фикстура JSON устарела. А так как у фикстуры JSON нет свойства name, вы получаете следующую ошибку: Теперь вы должны добавить свойство name ко всем 52 пользовательским JSON фикстурам. Это можно решить с помощью Typescript. Переместив JSON из файла исправления в .ts файл, компилятор Typescript найдет для вас ошибку: И мы обновим тестовый код, чтобы использовать этот новый объект. Спасибо Typescript! Как только вы решите проблему с компилятором, добавив name: 'Bob Smith' в GeneralUser:, код компилируется чисто, а лучше всего то, что ваш тест снова пройдет! Вы достигли одной из трех наших целей, достигнув типобезопасности. К сожалению, проблема высоко сцепления все еще существует. Например, что происходит, когда появляется разработчик, который еще новичок в юнит-тестировании. Все, о чем думается, это то, что надо проверить основное свойство, которое включает в себя удаленного пользователя. Поэтому они добавляют deleted: false в объект generalUser. Бабах! Ваш тест не проходит, и их тест проходит. Вот что значит быть высоко сцепленным. Поэтому разработчик тратит несколько минут (или часов) на дебаггинг и понимает, что оба теста имеют одни и те же базовые данные. Таким образом, разработчик использует простое (но недальновидное решение) из предыдущих и создает другой объект deletedUser, так что есть 1 объект на тест. Это может быстро выйти из-под контроля — я видел файлы тестовых данных длиной 5000 строк. Здесь можно увидеть, как странно это может выглядеть. Должен быть путь получше. Так как же нам рефакторить огромный файл объектов? Сделаем одну функцию! Теперь каждый тест может просто вызвать makeFakeUser(), когда он хочет создать пользователя. И самое лучшее в этом то, что, делая все случайным в фабричной функции, это показывает, что ни один отдельный тест не принадлежит этой функции. Если тест является особым видом IUser, то позже придется модифицировать его самостоятельно. И это легко сделать. Давайте представим себе удаленный пользовательский тест, где нас не волнует имя пользователя или что-то в этом роде. Нас волнует только то, что они удалены. Для меня, прелесть этого подхода в том, что он сам себя документирует. Любой, кто смотрит на этот тестовый код, должен понимать, что когда API возвращает удаленного пользователя, мы должны найти "Access Denied" на странице. Но я думаю, что мы сделаем это еще чище. Выше допускалось использование оператор spread, так как это был небольшой объект. Но это может быть более раздражающим, когда это вложенный объект, как этот: Вы не захотите, чтобы сотни таких объектов возникали. Так что если мы позволим пользователям переопределять только то, что они хотят, мы сможем создать действительно простой и базовый код DRY. Представьте себе, что есть очень специфический тест, в котором должен быть пользователь, живущий на "Main Street". Ого, нужно было только указать то, что нужно для теста, а не другие 7 свойств. И нам не пришлось хранить одноразовый объект в каком-то огромном тестовом файле. И мы также достигли своих целей. И как нам улучшить нашу функцию makeFakeUser для поддержки такого рода частичного переопределения?  Посмотрите, насколько легко это делает библиотека mergePartially (полное раскрытие: я сопровождающий mergePartially). Спасибо за то, что вы прочитали, как мы перешли от нестабильного и огромного тестового кода к маленькому и независимому. Я был бы рад услышать от вас, что вы думаете об этом подходе. Узнать больше о курсе «JavaScript QA Engineer».  Зарегистрироваться на открытый вебинар на тему «Что нужно знать о JS тестировщику».   Редактор