Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does clojure need dependency injection to make code more testable?

I remember reading an article about how Ruby doesn't really need DI or DI frameworks because the classes are open. As a result, you can simply rewrite a dependency's constructor so that it returns a fake object.

I'm very new to Clojure and functional programming. I'm wondering if Clojure needs dependency injection or it can forgo it for similar/other reasons. Here's a concrete example to work with (feel free how to point out how my design is non-idiomatic of Clojure):

Imagine you're developing a web crawler/spider. It needs to traverse a webpage you've downloaded. This is an action with side-effects. The webpage could change on every query, your internet connection could cut out, etc. It finds all the links on the webpage, visits each one, and then traverses it in the same way.

Now, you want to write a test that mocks out the http client so it returns a hard coded string response instead. How do you call the program's -main in a test and prevent it from using the real http client?

like image 872
Daniel Kaplan Avatar asked Mar 29 '13 02:03

Daniel Kaplan


People also ask

Why is dependency injection useful?

Dependency injection helps to develop testable code, allowing developers to write unit tests easily. You can use mock databases with dependency injection, and test your application without affecting the actual database.

Is there dependency injection in functional programming?

Dependency Injection is a technique to make the classes in Object Oriented Programming easier to test and configure. Instead of a class instantiating its own concrete implementations, it instead has them injected into it. In Functional Programming, that's a fancy way of saying “calling a function with parameters”.

Is dependency injection a design pattern?

In software engineering, dependency injection is a design pattern in which an object or function receives other objects or functions that it depends on. A form of inversion of control, dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs.

What is dependency injection in Javascript?

Dependency Injection (or DI for short) is a way of constructing your application so that you are not creating dependencies locally, but instead are being provided those dependencies from somewhere else in your application.


1 Answers

The with-redefs macro in clojure.core is very useful for stubbing out functions.

Here's a short REPL session to demonstrate this:

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"

Since a Clojure program is composed (mostly) of functions, not objects, dynamic rebinding of functions replaces a good deal of what a DI framework would do for testing purposes.

like image 52
quux00 Avatar answered Oct 19 '22 03:10

quux00