hey folks! maybe it’s a silly question: how can I “mock” init methods? I know I can bring up a whole new system given a config… but what if I just want a certain component to be swapped for testing?
You can use keyword inheritance for this. For example, you might have a key :example/webserver. You could replace this with a key :example.mock/webserver that derives from the original.
That way you only have to replace one key in the configuration, and all the refs will work the same.
that would imply:
1. add new key :example.mock/webserver
2. create the init defmethod for it
3. substitute all deps from :example/webserver to :example.mock/webserver
am I seeing this correctly?
Almost: you wouldn't need to substitute all deps if you used derive. You could also create a single :example/mock key and use composite keys: [:example/mock :example/webserver] .
(defmethod :mock/server [_ _]
{:started? true})
(derive :mock/server :real/server)
(def mock-config
(-> config
(assoc :mock/server (:real/server config))
(dissoc :real/server)))You could also use a mocking library to mock out init-key.
(require '[clojure.set])
(defmethod ig/init-key :mock/server [_ _]
(println "MOCK"))
(defmethod ig/init-key :real/server [_ _]
(println "REAL"))
(defmethod ig/init-key :dep/stuff [_ _]
(println "DEP"))
(derive :mock/server :real/server)
(def config
{:real/server {}
:dep/stuff (ig/ref :real/server)})
(def mock-config
(clojure.set/rename-keys config {:real/server :mock/server}))
(ig/init mock-config)
(ig/init config)You probably want (:real-server config) instead of (:real-server {}) (which is always nil ).
You could also use clojure.set/replace-keys in place of assoc/dissoc:
(set/replace-keys config {:real/server :mock/server})