The Speclj framework

The Speclj framework (https://github.com/slagyr/speclj) is a TDD/BDD[7] testing framework based on RSpec[8]. Behavior Driven Development (BDD) is a type of Test Driven Development (TDD) that allows business and development teams to collaborate on software building. In BDD, the tests are described using English-like sentences that express the behavior of a program and the expected outcomes. In TDD, the tests are written first, before the actual code is implemented.

In order to use Speclj, we need to add it to project.clj:

(defproject testing-example "0.1.0-SNAPSHOT"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.9.0"]
[expectations "2.2.0-rc3"]
[midje "1.9.4"]
[speclj "3.3.2"]]
:plugins [[lein-expectations "0.0.8"]
[speclj "3.3.2"]])

Next, we will create a file, testing_example/speclj_tests.clj, in the test directory:

(ns testing-example.speclj-tests
(:require [speclj.core :refer :all]
[testing-example.core :refer :all]))

The Speclj framework provides a number of macros, such as context, describe, it, should, and should=, which help to create tests. Macros are composable, allowing developers to create tests that are read like English sentences.

The describe container is the outermost container for specs. It takes a string name and any number of spec components. context is used to nest the testing contexts inside of the outer describe:

(describe "Testing non-blank? function"
(context "Passing invalid values"
(it "is passed an empty string"
(should-not (non-blank? "")))
(it "is passed a nil"
(should-not (non-blank? nil))))
(context "Passing valid values"
(it "accepts letters"
(should (non-blank? "Some text")))
(it "accepts number strings"
(comment (should (non-blank? 1234)))
(should (non-blank? 1234)))))

When we run the tests, some of them will fail:

$ lein spec
...F

Failures:

1) Testing non-blank? function Passing valid values accepts numbers
java.lang.Long cannot be cast to java.lang.CharSequence
java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.CharSequence
... 3 stack levels elided ...
at testing_example.speclj_tests$eval10197$fn__10198$fn__10219$fn__10227.invoke(/testing-example/test/testing_example/speclj_tests.clj:16)
;;;
... 15 stack levels elided ...

Finished in 0,00071 seconds
4 examples, 1 failures

The stack trace tells us that our tests fail on line 16, where we used a number. Let's change the code, as follows:

(it "accepts number strings"
(should (non-blank? "1234")))

Now, the tests will pass, as shown in the following code snippet:

$ lein spec
....

Finished in 0,00044 seconds
4 examples, 0 failure

When we look at the tests, we can see that by using different macros, we can create tests that are read like English sentences.

The speclj.core namespace provides a number of should-like macros. The macros that we will cover are as follows:

These macros can help to create many tests. We will see them in action in the following sections.