Search code examples
unit-testingclojurecompojureringkorma

Compojure/ring app, initialize database outside test-scope


How do I intitailze my database so my (def db ...) will not attempt to initialize the database when running my unit-tests (since it will not be a database there then).

I mock the the sql and dml in functions (with-redefs) but all examples i have found so far simply define the database directly in the namespace (eg not wrapped in a function).


Solution

  • I strongly recommend you do not put your database in a Var. It's a very tempting, but quite harmful, form of environment coupling.

    The recommended way is to pass the database your database as an argument of whatever function needs access to it in its body:

    ;; BAD
    (def db ...)
    
    (defn find-user [user-id]
      (run-query find-user-query db user-id))
    
    ;; GOOD
    (defn find-user [db user-id]
      (run-query find-user-query db user-id))
    

    It's not as tedious as you'd think, and the benefits are great (for testing, repl-driven development, etc.).


    NOTE:

    In the early years of the Clojure community, people have been using dynamic Vars to avoid having to add a parameter all the time.

    (def ^:dynamic db nil)
    
    (binding [db ...]
      (find-user user-id))
    

    Then we learned to stop doing that :) complecting your logic with its environment is just a bad foundation for your programs.