Integration Testing Setup with Midje and Leiningen

Writing good tests is something that is important in virtually all software projects. In this blog we’ll use Midje and Leiningen for integration testing. Midje is a test framework for Clojure whose purpose is to provide a way to write readable tests (facts) easily. For example:

; Test1
(fact "Fact description"
	[1 2 3 4] => (just [odd? even? odd? even?]))

Leiningen is the de facto build tool for Clojure and Midje provides a plugin that allows you to run all Midje tests using:

lein midje

Tag facts as integration tests

While this works great you probably want to distinguish between unit tests (fast and small scope) and integration tests (slower and larger scope). Midje provides a to do this by using filters. For example we can use the :it keyword to tag our facts as integration tests:

; Test2
(fact "A slow integration test" :it
	(slow-network-stuff) => 42)

Running the integration tests from Leiningen now looks like this:

lein midje :filters it

This will run Test2 but not Test1. To run only the unit tests and not the integration tests we can do:

lein midje :filters -it

Add integration test source folder

By default all tests in Leiningen are located in the test folder. Placing both unit tests and integration tests in the same folder makes it hard to distingiush between them. I prefer to have a seperate folder for unit and integration tests. It’s easy to do this in Leiningen once you know how it’s done. All you need to do is to specify the :test-paths key in Leiningen’s project.clj:

...
:test-paths ["test" "itest"]
...

Here we add the itest folder to the test classpath. Thus we can place all our integration tests in this folder and have them separated from our unit tests.

Aliases

In order to write less and make it a bit easier to remember how to apply Midje filters we can make aliases for running our tasks in Leiningen. First we’ll create an alias for running the integration tests in our project.clj:

:aliases {"itest" ["midje" ":filters" "it"]}

This allows us to run the integration tests from Leiningen using:

lein itest

Likewise we can add an alias (utest) for running only the unit tests:

:aliases {"itest" ["midje" ":filters" "it"]
		  "utest" ["midje" ":filters" "-it"]}

If we’re only using Midje in the project we could replace the standard test task with Midje:

:aliases {"itest" ["midje" ":filters" "it"]
		  "utest" ["midje" ":filters" "-it"]
		  "test"  ["midje"]}

Running lein test now will execute all Midje tests (both unit and integration tests).

Summary

Both Midje and Leiningen are flexible enough to allow us to configure our test environment as we find fit. A full example of a project.clj file configured with the above settings is shown here:

(defproject test-project "0.1.0-SNAPSHOT"
            :description "FIXME: write description"
            :url "http://example.com/FIXME"
            :license {:name "Eclipse Public License"
                      :url  "http://www.eclipse.org/legal/epl-v10.html"}
            :dependencies [[org.clojure/clojure "1.6.0"]]
            :min-lein-version "2.0.0"
            :profiles {:dev        
            				{
                               :dependencies [[midje "1.6.3"]]
                               :plugins      [[lein-midje "3.1.3"]]                                     
                            }                       
                       }            
            :test-paths ["test" "itest"]
            :aliases {"itest" ["midje" ":filters" "it"]
                      "test"  ["midje"]
                      "utest" ["midje" ":filters" "-it"]})

Happy testing!

This Post Has 4 Comments

  1. Guy

    Hey Johan,
    Great post! I’ve been trying to find a simple and easy way of running integration tests and this seems to be it!
    One question though, have you tried using midje with fixtures?

    1. Johan Haleby

      Thanks. Unfortunately I haven’t used midje fixtures.

  2. Guy

    Ah not to worry! Thanks again :)

  3. Andy

    This was just the article I was looking for – thanks Johan.

Leave a Reply