Повышение тестируемости с внедрением зависимостей в JavaScript: практические примеры

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

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

Тестируемость — это простота тестирования нашего кода.

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

Тестирование…

«Тестирование, тестирование, тестирование» — мы так часто слышим это. Что это вообще значит?

Как программисты, мы все время тестируем — запускаем команду на терминале, тестируем API с помощью такого инструмента, как Postman и т. д. Единственная разница в том, что большинство из нас тестирует код вручную. Когда я говорю тестирование, я имею в виду автоматизированное тестирование.

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

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

Быстрая установка

Лично мне нравится использовать Jest и Sinon для написания тестов. Jest — это среда тестирования, которую легко настроить и с которой легко работать, как и Sinon.

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

Давайте добавим эти инструменты в наш проект.

yarn add -D jest sinon @types/jest

Бесстыдная вилка: если вы хотите узнать, как работает Синон, посмотрите мое видео на YouTube или эту статью

Как только это будет сделано, мы обновим файл package.json, чтобы мы могли легко запускать наши тесты из CLI с помощью npm run test, например так

{
  "name": "coffee-shop",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "test": "jest"
  },
  "devDependencies": {
    "@types/jest": "^29.5.2",
    "jest": "^29.5.0"
  }
}

Наконец, мы добавим каталог test. Jest по умолчанию ищет тестовые файлы в этом каталоге и любые файлы, оканчивающиеся на .spec.js или .test.js.

Ваш первый тест

Мы напишем тесты для класса бариста Джейн.

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

При тестировании мы следуем структуре под названием Arrange Act Assert . Это просто означает, что для каждого теста мы

  1. Организуйте — мир, создавая экземпляры, настраивая начальные данные и т. д.…
  2. Act — вызвать функцию или класс, которые мы тестируем. Это также называется тестируемой системой (или SUT).
  3. Утвердите — или убедитесь, что результат вызова SUT — это то, что вы ожидаете.

Выполнение вышеуказанного с npm run test приводит к следующему

Хорошо хорошо. Все это прекрасно, но где же эта «сила DI», о которой вы говорите? Мне нравится твой энтузиазм! Давайте копать.

Сгибание кода

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

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

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

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

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

Там! Наши тесты снова стали зелеными.

Если вы не заметили, здесь есть закономерность. Каждый из приведенных выше примеров имел следующую форму:

  1. Напишите тестовый сценарий
  2. Запустите тест и убедитесь, что он не работает
  3. Обновите код для обработки сценария
  4. Повторно запустите тест и убедитесь, что он прошел.

Этот цикл известен как цикл Red-Green-Refactor и является мантрой разработки через тестирование.

Заключение

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

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

Буду рад узнать, что вы думаете об этих статьях!
Полезны ли они? О чем вы хотите узнать больше? React, Node/Express/базы данных и ORM?

Я работаю инженером полного цикла около 9 лет и обладаю обширным опытом: от веб-разработки с помощью React и Vue до проектирования микросервисов и настройки и автоматизации инфраструктуры.

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

До скорого…