Has anyone written a guide on how tests runners work with an Integrant project? Trying to find a good pattern to give my tests access to the database connection.
I think you are over-complicating things 🙂 Consider your test util looks like this:
(ns gr.cons.river.test-utils
(:require
[gr.cons.river.core :as core]
[integrant.repl.state :as state]
[next.jdbc :as jdbc]))
(defn system-state
[]
(or @core/system state/system))
(defn db []
(:db.sql/connection (system-state)))
(defn with-empty-db []
(fn [f]
(jdbc/execute! (db) ["truncate table nodes restart identity cascade"])
(jdbc/execute! (db) ["truncate table posts restart identity cascade"])
(jdbc/execute! (db) ["truncate table releases restart identity cascade"])
(jdbc/execute! (db) ["truncate table users restart identity cascade"])
(f)))
(defn system-fixture
[]
(fn [f]
(when (nil? (system-state))
(core/start-app {:opts {:profile :test}}))
(f)
(core/stop-app)))
and then in your tests you can just use the db directly:
(ns gr.cons.river.core-test
(:require
[gr.cons.river.test-utils :as tu]
[gr.cons.river.web.models.nodes :as domain]
[gr.cons.river.web.models.users :as users]
[clojure.test :refer :all]))
(use-fixtures :once (tu/system-fixture))
(use-fixtures :each (tu/with-empty-db))
(deftest example-test
(let [;; truncated
user-1 (users/insert-user (tu/db) "foo")
user-2 (users/insert-user (tu/db) "bar")
]
(domain/insert-posts (tu/db) (:id release-1) files-1)
;; test setup
(testing "first release for first user"
(is (= [{:depth 1
:post-id 1
:visited true}
{:depth 2
:post-id 2
:visited true}
{:depth 3
:post-id 3
:visited false}
{:depth 4
:post-id 4
:visited false}
{:depth 5
:post-id 5
:visited false}] (map #(select-keys % [:post-id :depth :visited]) (domain/find-path-for-user (tu/db) (:id release-1) (:id user-1))))))
;; truncated
))hope that helps
Right that's interesting. It looks like you've engineered it so it works in both repl, where you already have the system running, or when run on command-line.
That's really helpful kongeor, thanks. With your help I now have a solution that's working well for me!
indeed, this works on repl, integration tests, and production builds 🙂 happy to hear it works well ❤️
I'm using clj kit for a project which comes with a utility for test fixtures: e.g. https://github.com/kit-clj/kit-examples/blob/master/guestbook/test/clj/kit/guestbook/test_utils.clj
then you can just have a function like this:
(defn db []
(:db.sql/connection (system-state)))alright, thanks. that's good to look at
So kit is keeping system in an atom to make it easier to access from other namespaces. Interresting.
The alternative option I guess is to make an entirely different integrant system for testing. But then I think I can't use the cognitect test runner because that doesn't have the ability to pass state around the way I need.
Even ignoring the cognitect test runner and looking at clojure.test, I see that deftest takes no arguments. So no particular way to pass a database connection to tests. So perhaps an atom is required to share system state with the tests. Unless I ignore deftest and just make functions that call the "is" macro directly. Just trying to figure out if there is a standard pattern to do this sort of stuff with integrant.
Hi guys, is there any way to have access in a value of a config key? Let's say I have the following config
(defmethod ig/init-key :auth/keycloak
[_ config]
(assoc config :access-token (atom {:token nil
:retry-counter 0})))
I want to use this access-token from other ns. How can I access it ?I'm afraid I don't fully understand the question, unless you're asking about refs (in which case, you can use integrant.core/ref).