3

I have seen many clojure projects that disable integration tests by default by adding this setting to project.clj:

:test-selectors {:default (complement :integration)
                 :integration :integration}

But, if a namespace contains only integration tests, the fixtures in it still run when I run lein test!

For example if I run lein new app test and make the contents of core_test.clj this:

(defn fixture [f]
  (println "Expensive setup fixture is running")
  (f))
(use-fixtures :once fixture)

(deftest ^:integration a-test
  (println "integration test running"))

Then when I run lein test I see the fixture running even though no tests are run.

What is the correct way to handle this in clojure?

4

2 回答 2

3

One way to accomplish not running the expensive computation is to take advantage of the fact that even though the :once fixtures will run regardless of whether there are tests to run in the ns or not, the :each fixtures will only run on each actually-running test.

Instead of doing the actual computation (or acquiring resources like a db connection, or doing whatever side-effects) in the :once fixture, we only do it in the first (we want to do it only once!) :each fixture, for example doing as following:

(def run-fixture? (atom true))

(defn enable-fixture [f]
  (println "enabling expensive fixture...")
  (try
    (f)
    (finally (reset! run-fixture? true))))

(defn expensive-fixture [f]
  (if @run-fixture?
    (do
      (println "doing expensive computation and acquiring resources...")
      (reset! run-fixture? false))
    (println "yay, expensive thing is done!"))
  (f))

(use-fixtures :once enable-fixture)
(use-fixtures :each expensive-fixture)

(deftest ^:integration integration-test
  (println "first integration test"))

(deftest ^:integration second-integration-test
  (println "second integration test"))

The output of lein test will be as following (notice how the enable-fixture has run but not the expensive expensive-fixture):

› lein test

lein test fixture.core-test
enabling expensive fixture...

Ran 0 tests containing 0 assertions.
0 failures, 0 errors.

When running lein test :integration, the expensive-fixture will run exactly once:

› lein test :integration

lein test fixture.core-test
enabling expensive fixture...
doing expensive computation and acquiring resources...
first integration test
yay, expensive thing is done!
second integration test

Ran 2 tests containing 0 assertions.
0 failures, 0 errors.
于 2016-12-10T01:18:25.843 回答
1

It seems like the fixture is running regardless of whether the tests run. Then, you could put the fixture functionality into the test itself to "manually" control that setup/teardown. Pseudocode:

(defn run-all-tests []
  (do-test-1)
  ...
  (do-test-N))

(deftest ^:slow mytest
  (do-setup)
  (run-all-tests)
  (do-teardown))
于 2016-12-07T06:10:54.870 回答