integrant

Otto Nascarella 2023-08-02T10:56:45.353119Z

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?

❤️ 1
weavejester 2023-08-02T10:58:39.765559Z

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.

weavejester 2023-08-02T10:58:59.149549Z

That way you only have to replace one key in the configuration, and all the refs will work the same.

Otto Nascarella 2023-08-02T11:02:44.039129Z

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?

weavejester 2023-08-02T11:04:22.052249Z

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] .

weavejester 2023-08-02T11:07:26.155169Z

(defmethod :mock/server [_ _]
  {:started? true})

(derive :mock/server :real/server)

(def mock-config
  (-> config
      (assoc :mock/server (:real/server config))
      (dissoc :real/server)))

weavejester 2023-08-02T11:08:14.321959Z

You could also use a mocking library to mock out init-key.

Otto Nascarella 2023-08-02T12:25:42.259219Z

(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)

weavejester 2023-08-02T12:28:38.619999Z

You probably want (:real-server config) instead of (:real-server {}) (which is always nil ).

weavejester 2023-08-02T12:29:39.004969Z

You could also use clojure.set/replace-keys in place of assoc/dissoc:

(set/replace-keys config {:real/server :mock/server})

1