Подтвердить что ты не робот

Требуется ли clojure инъекция зависимости, чтобы сделать код более подверженным тестированию?

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

Я очень новичок в Clojure и функциональном программировании. Мне интересно, нужна ли Clojure инъекция зависимостей или она может отказаться от нее по аналогичным/другим причинам. Вот конкретный пример работы (не стесняйтесь, как указать, как мой дизайн не идиоматичен Clojure):

Представьте, что вы разрабатываете веб-гусеничный/паук. Он должен пройти веб-страницу, которую вы загрузили. Это действие с побочными эффектами. Веб-страница может меняться при каждом запросе, вы можете отключить интернет-соединение и т.д. Он находит все ссылки на веб-странице, посещает их, а затем обходит их так же.

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

4b9b3361

Ответ 1

Макрос with-redefs в clojure.core очень полезен для выполнения функций-заглушек.

Здесь короткий сеанс REPL, чтобы продемонстрировать это:

user=> (defn crawl [url]
  #_=>   ;; would now make http connection and download content
  #_=>   "data from the cloud")
#'user/crawl
user=> (defn -main [& args]
  #_=>   (crawl "http://www.google.com"))
#'user/-main
user=> (-main)
"data from the cloud"
user=> (with-redefs [crawl (fn [url] "fake data")]
  #_=>   (-main))
"fake data"

Так как программа Clojure составлена ​​(в основном) из функций, а не объектов, динамическое переупорядочение функций заменяет собой то, что будет делать инфраструктура DI для целей тестирования.

Ответ 2

В Clojure вы обычно достигаете эквивалента инъекции зависимостей с помощью альтернативных методов:

  • Динамическое связывание - например. полезно для перенаправления стандартного вывода в тестовые функции, выполнив (binding [*out* some-writer-object] ...)
  • Функции более высокого порядка - могут использоваться для обеспечения формы инъекции зависимостей путем передачи других функций в качестве параметров
  • Конфигурация с данными - это довольно идиоматично в Clojure, чтобы передавать карты, содержащие параметры конфигурации (или даже функции для настройки пользовательского поведения).

Все они являются неотъемлемой частью самого языка. Поэтому вам определенно не нужно ничего, как "каркас DI". IMHO, нуждающийся в каркасе для DI, действительно просто компенсирует отсутствие достаточных возможностей в самом языке.

Ответ 3

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

Я не вижу необходимости в инъекции зависимостей здесь. Здесь, как я думаю, я бы решил эту проблему, сохраняя при этом тестируемость: выделите реализацию как минимум на две функции. Одна функция извлекает и возвращает веб-страницу, а другая анализирует ответ. В вашей основной функции у вас будет что-то вроде (-> "http://google.com" fetch parse).

Затем, чтобы протестировать parse, вы можете просто обойти метод fetch и подавать фальшивые данные веб-страницы непосредственно в метод parse.

(deftest test
     (is (= {:something "blah"} (parse "<html><head><title>Fake webpage etc..</title></head></html>"))))

До тех пор, пока вы будете осторожны в решении проблем с ясными функциями, я не думаю, что вам нужно что-то сложное, как DI для тестирования.

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