5. Test with test-is
Write test with this!!
(clojure.contrib.test-is/deftest testname & forms)
Use 'is' Macro instead of assertions.
(clojure.contrib.test-is/is form message?)
Ready to run all tests?
(clojure.contrib.test-is/run-tests & namespaces)
6. Test with test-is
(deftest test-that-demonstrates-failure
(is (= 5 (+ 2 2))))
(run-tests)
Testing user
FAIL in (test-that-demonstrates-failure) (NO_SOURCE_FILE:5)
expected: (= 5 (+ 2 2))
actual: (not= 5 4)
Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
8. Other Options for Test
All Clojure sequences implement Java collection interfaces.
All Clojure functions implement Callable and Runnable.
So, you can write your tests with any Java-compatible test
framework:
JUnit, TestNG, or even EasyB or JTestR.
Good luck!
9. Data Access
clojure.contrib.sql -> thin wrappers for JDBC
The entry point for sql is the with-connection macro:
(clojure.contrib.sql/with-connection db-spec & body)
(use 'clojure.contrib.sql)
; START: db
; replace "snippet-db" with a full path!
(def db {:classname "org.hsqldb.jdbcDriver"
:subprotocol "hsqldb"
:subname "file:snippet-db"})
; END: db
; db-spec -> JDBC's DriverManager
10. Data Access
Create Table by create-table function
(clojure.contrib.sql/create-table name & column-specs)
(use 'clojure.contrib.sql)
(defn create-snippets []
(create-table :snippets
[:id :int "IDENTITY" "PRIMARY KEY" ]
[:body :varchar "NOT NULL" ]
[:created_at :datetime]))
(with-connection db (create-snippets))
(0)
(with-connection db (create-snippets)))
java.lang.Exception: transaction rolled back: failed batch
12. Data Access
issues some sql and then executes
the forms in body with results
->
with-query-results
(with-query-results results sql & body)
(defn print-snippets []
(with-query-results res ["select * from snippets" ]
(println res)))
(with-connection db (print-snippets))
({:id 0, :body (println :boo),
:created_at #<Timestamp 2009-01-03 11:40:19.985>}
{:id 1, :body (defn foo [] 1),
:created_at #<Timestamp 2009-01-03 11:40:19.985>})
13. Data Access
; Broken!
(defn select-snippets []
(with-query-results res ["select * from snippets" ] res))
(with-connection db (select-snippets)))
java.sql.SQLException: No data is available
JDBC results can be lazy & select-snippets return lazy seqs
(defn sql-query [q]
(with-query-results res q (doall res)))
(with-connection db (sql-query ["select body from snippets"]))
14. Data Access
transaction macro
(clojure.contrib.sql/transaction & body)
; ID of the new snippet
(defn last-created-id [] (first (vals (first (sql-query ["CALL IDENTITY()" ])))))
(defn insert-snippet [body]
(with-connection db
(transaction
(insert-values :snippets
[:body :created_at]
[body (now)])
(last-created-id))))
(insert-snippet "(+ 1 1)")
) 4
(insert-snippet "(ref true)")
) 5
15. Other library Options
Higher level tool options
-> use a java framework(Hibernate,iBatis,ActiveRecord..)
-> use a clojure-specific persistence libraries(clj-
record,clojureql)
clj-record example
(ns clj-record.test.model.manufacturer
(:require [clj-record.core :as cljrec])
(cljrec/init-model
(has-many products)
(validates name "empty!" #(not (empty? %)))
(validates name "starts with whitespace!" #(not (re-find #"^s" %)))
(validates name "ends with whitespace!" #(not (re-find #"s$" %)))
(validates grade "negative!" #(or (nil? %) (>= % 0))))
clojureql example
(execute (sql
(query [id name] developers.employees (and (> id 5) (< id 8)))))
16. Web DevelopmentCompojure & Jetty web server
simple routes create by defroutes
(compojure/defroutes name doc & routes)
routes (HTTP-VERB url-pattern body)
run-server
(compojure/run-server options? & paths-and-servlets)
(use 'compojure)
(defroutes snippet-app
"Create and view snippets."
(GET "/ping" "pong" )
(ANY "*"
(page-not-found)))
(run-server {:port 8080}
"/*" (servlet snippet-app))
17. Building HTML
test-area function
(compojure/text-area options? name value?)
html function to actual html
(compojure/html & trees)
(use 'compojure) (text-area "body"))
[:textarea {:id "body", :name "body"} nil]
(println (html (text-area "body")))
<textarea id="body" name="body"></textarea>