Lepší testování v Clojure: Midje

Dneska navážu na unit testování v Clojure, nicméně dostanu se k tomu oklikou. Minulé léto se celkem hojně psalo o desátém výročí deklarace Manifesto for Agile Software Development. Internetem (a mojí čtečkou) tehdy protekly nějaké rozhovory s někdejšími účastníky/signatáři. Jedním z nich byl i Brian Marick, autor Midje, testovacího frameworku pro Clojure (ano, to je to Midje, které jsem zmiňoval ve svém postu o ThoughtWorks Radar).

Instalace/zprovoznění

Midje je nejjednodušší začít používat pomocí Leiningenu (určitě jeden z příštích zápisků). Definice projektu může vypadat třeba takto:

(defproject blog-midje "1.0.0-SNAPSHOT"
  :description "Midje for Sometimes Clojure"
  :dependencies [[org.clojure/clojure "1.3.0"]]
  :dev-dependencies [[midje "1.3.2-SNAPSHOT"]])

REPL se pak spustí příkazem lein repl.

Fakta

Základem testování v Midje jsou fakta. Fakta o budoucím kódu (test first):

(ns blog-midje (:use midje.sweet))
; nil
(fact (+ 1 1) => 2)
; true
(fact 1 => odd?)
; true
(fact "truth about one" 1 => even?)
; FAIL at (NO_SOURCE_FILE:11)
; Actual result did not agree with the checking function.
;         Actual result: 1
;     Checking function: even?
; false

Fakt může mít více klauzulí. Dá se použít makro fact nebo facts:

(facts "about42"
       (+ 21 21) => 42
       (* 6 7) => 42)
; true

Pokud je potřeba fakt prezentovat pomocí sady hodnot, nabízí Midje tzv. tabulková fakta:

(defn xor [x y]
  (if (= x y) false true))

; #'blog-midje/xor
(tabular
  (fact "The rules of XOR"
        (xor ?x ?y) => ?expected)
  ?x    ?y    ?expected
  0     0     false
  0     1     true
  1     0     true
  1     1     false
  false false false
  false true  true
  true  false true
  true  true  false)
; true

Vyhození výjimky se dá otestovat pomocí funkce (checkeru) throws:

(fact (/ 42 0) => (throws ArithmeticException))
; true

Spuštění testů

Midje předpokládá pro spuštění (všech) testů nějaký nástroj, jako např. Leiningen nebo Cake. Pojďme se podívat, jak by vypadalo rozchození projektu a testů pomocí Leiningenu. Nový projekt vytvoříme příkazem: lein new blog-midje

Struktura projektu by měla vypadat takto:

Layout projektu

Layout projektu

Do definice projektu (project.clj) je potřeba přidat závislosti. Kromě těch obligátních je to hlavně knihovna lein-midje:

(defproject blog-midje "1.0.0-SNAPSHOT"
            :description "Midje for Sometimes Clojure"
            :dependencies [[org.clojure/clojure "1.3.0"]]
            :dev-dependencies [[midje "1.3.2-SNAPSHOT"]
                               [lein-midje "1.0.8"]])

Prvně napíšeme test (soubor test/blog_midje/test/core.clj):

(ns blog-midje.test.core
  (:use [blog-midje.core])
  (:use [midje.sweet]))
(tabular
  (fact "The rules of XOR"
        (xor ?x ?y) => ?expected)
  ?x    ?y    ?expected
  0     0     false
  0     1     true
  1     0     true
  1     1     false
  false false false
  false true  true
  true  false true
  true  true  false)

Potom napíšeme testovanou funkci (src/blog_midje/core.clj):

(ns blog-midje.core)
(defn xor
    "Returns true if x and y are mutually exclusive."
    [x y]
    (if (= x y) false true))

Testy potom spustíme příkazem lein test, nebo lépe lein midje:

Spuštění testů

Spuštění testů

Celý projekt je ke stažení zde: blog-midje.zip.

[Update] Celý projekt je dispozici na Bitbucketu:

[/Update]

To je pro dnešek vše. Pokud se chcete podívat na úvod do Midje od samotného Briany Maricka, zkuste videa uvedená na wiki stránce Midje.