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

Приложение для дождливых дней

Нам дали задание написать зонтичное рекомендательное приложение. У нас есть доступ к внешнему API прогноза погоды, который позволяет нам запрашивать прогнозы погоды на определенную дату. Нам нужно определить, должен ли пользователь носить зонт сегодня. Давайте посмотрим на этот пример кода:

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

Попробуем наивно написать юнит-тест:

Что происходит в этом блоке кода:

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

Так что же сломало тест? У нас даже нет заранее определенного входа. UmbrellaRecommender зависит от реальной службы погоды. Возвращаемое значение реального сервиса зависит от реальных данных. Это не то, чего мы хотим. Мы просто хотим проверить логику рекомендателя независимо от реальных данных.

Изоляция зависимости

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

Как мы его абстрагируем? Используя интерфейс, конечно:

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

Теперь мы внедряем интерфейс IWeatherService вместо того, чтобы использовать реальный экземпляр службы погоды. Это позволяет нам передать конструктору реальный или поддельный погодный сервис. Мы перепишем наши тесты, чтобы передать конструктору экземпляр WeatherServiceStub. Мы изменим свойство вероятности дождя, чтобы проверить различные случаи.

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

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

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

Пример репозитория можно найти по адресу: https://github.com/basarozogut/UmbrellaRecommenderApp-Medium

Связанные темы для проверки