Search code examples
clojurelet

Reusing the same let bindings


I'm refactoring my test suite for a clojure application and am trying to figure out if there is a way to save let bindings for reuse to minimize copied code, as many tests require the similar setup but interfere with each other and require their own deftest. Ideally, I would like it to work a little like this:

(def let-bindings [bind1 val1 bind2 val2 bind3 val3])

(deftest test-1
  (testing "my test"
    (let (conj let-bindings [bind4 val4])
      ...)))

(deftest test-2
  (testing "my second test"
    (let (conj let-bindings [bind5 val5])
      ...)))

For added clarification, I need val1 and val2 to be evaluated in the test, not when defining the let bindings, as the calls affect the test database in a way that needs to be reset after each test. Does this mean I need a macro?


Solution

  • let is a special form so trying to metaprogram it without doing it in a macro won't work. Perhaps you should just define the common bindings instead:

    (def bind1 val1) 
    (def bind2 val2) 
    (def bind3 val3)
    
    (deftest test-1
      (testing "my test"
        (let [bind4 val4]
          ;; here bind1...bind4 would be available
          ...)))
    
    ...
    

    EDIT

    Here is how I imagine you could do it with a macro:

    ;; notice that the let will be recreated each time so if
    ;; val1 ... are computational hard consider caching. 
    (defmacro elet [ bindings & body ] 
      `(let [bind1 val1 bind2 val2 bind3 val3 ~@bindings] 
         ~@body))
    
    (deftest test-1
      (testing "my test"
        (elet [bind4 val4]
          ;; here bind1...bind4 would be available
          ...)))
    
    ...