5

Testing in Clojure (Part-1: Unit testing)

 3 years ago
source link: https://blog.knoldus.com/testing-in-clojure-part-1-unit-testing/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Testing in Clojure (Part-1: Unit testing)

Reading Time: 3 minutes

Testing a web application in Clojure is as important as testing in any other language. Clojure testing has been made simpler with its built in unit tests.

This blog explains about how to do unit testing(testing each module independently) of Clojure methods with some very basic syntax.

For Clojure testing we would be using a clojure.test testing namespace to load testing framework for placing the midje framework test cases.

xxxxxxxxxx
(ns testing-namespace
(:use clojure.test))

Firstly, add the following dependencies and plugins of Midje testing framework in your project.clj file:

xxxxxxxxxx
:plugins [lein-midje "3.1.3"]
:dependencies [midje "1.6.2"]

testing framework gives you choice from using any of the two test defining methods:

  1. defining test using with-test followed by method defination and test case.
xxxxxxxxxx
(with-test
(defn sum[s]
(+ s 2))
 (is (= 3 (sum 1)))

2. or defining your test cases in a seperate file using deftest macro(test function with no arguments) which improves the code quality.

Example: create two separate files-

method.clj

xxxxxxxxxx
(ns method.routes.core)
(defn truthy? [value]
 (if (= value "true")
 true
 false))
(defn valid? [id email]
 (vali/rule (vali/has-value? id)
 [:id "Username required"])
 (vali/rule (vali/is-email? email)
 [:email "Invalid Email Address"
 ])
(defn change-profile [old-password new-password confirm-password user]
 (if (password-match? old-password user)
 (if (confirmation-check? new-password confirm-password)
 (do
 -------------
 (profile confirm-password))
 (do
 (vali/rule false
 [:no-match "Password does not match"])
 (profile old-password))))
(defn password-match[ old-password user]
;;------------------------)
(defn confirmation-check[new-password confirm-password]
;;-------------------------)

methodTest.clj (Test file)

below namespace definition also requires importing the namespace of the file where the methods to be tested are defined followed by :refer :all for refering to every method in this namespace. Noir.util.test is required only to test those methods which uses clojure noir library validation checks.

xxxxxxxxxx
(ns example.test.methodTest
 (:use clojure.test
 example.handler
 noir.util.test)
 (:require [method.routes.core :refer :all]))
(deftest truthy-testing
;;for true test case:
 (is(truthy? "true")))
;;for false test case:
 (is(truthy? "false"))))

(for leiningen clojure framework we are using lein test command in terminal within project name path to run the test.)

xxxxxxxxxx
;;output for true test case i.e; no exception shown by passing expected value same as actual
lein test example.test.methodTest
Ran 1 tests containing 1 assertions.
0 failures, 0 errors.
;; output for false test case i.e;failure occured by passing expected value not same as actual
FAIL in (truthy-testing) (methodTest.clj:9)
expected: (truthy? "false"))
 actual: (not (truthy? "false"))
Ran 1 tests containing 2 assertions.
1 failures, 0 errors.
Tests failed.

Another example test case for testing validation method :

xxxxxxxxxx
(deftest -validation-test
(is (with-noir (auth/valid? "username" "[email protected]")) "message: valid")
 (is (with-noir (auth/valid? "" "[email protected]" )) "message: null value in a string")
 (is (with-noir (auth/valid? "username" "username")) "message: Invalid Email Address"))

output: first assertion shows true with no error message, rest 2 assertion gives described error message and failure test case

xxxxxxxxxx
lein test example.test.methodTest
lein test :only example.test.methodTest/validation-test
FAIL in (validation-test) ( methdTest.clj:18)
message: null value in a string
expected: (with-noir (auth/valid? "" "[email protected]"))
 actual: false
lein test :only example.test.methodTest/validation-test
FAIL in (validation-test) (methodTest.clj:19)
message: Invalid Email Address
expected: (with-noir (auth/valid? "username" "username"))
 actual: false
Ran 1 tests containing 3 assertions.
2 failures, 0 errors.
Tests failed.

Example Test case for testing nested method by unit testing method

xxxxxxxxxx
(deftest change-profile-test
 (is (= true (with-noir (password-match? "1234567890" "username")))"not found in database")
 (is (= true (with-noir (confirmation-check? "1234" "1234")))"invalid")
 (is (= true (with-noir (update-profile "1234567890" "1234" "1234" "username")))))

output: shows true result with no error message as the same data exists in database for “username”

xxxxxxxxxx
lein test example.test.methodTest
Ran 1 tests containing 1 assertions.
0 failures, 0 errors

Note:

*(is) in above test cases checks a single instance of method and throws exception if   fails.Multiple assertions can also be checked within a single method by just defining multiple arguments and not same method again and again using(are).

*lein test command runs all tests in all namespaces. One can test the test cases under a single namespace also using lein test ‘your.namespace’.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK