Skip to content
Brenton Ashworth edited this page Jul 2, 2013 · 7 revisions

Testing

In this section you will be introduced to the following Pedestal concepts:

  • testing behavior code
  • sharing Clojure and ClojureScript code

Testing behavior

Before we move on to the next section, we should spend a moment thinking about testing. At this point we have some behavior and it is easy enough to test it by refreshing the browser. As an application grows this will be harder to do. It would be good to have some automated tests in place.

In the file tutorial-client/test/tutorial_client/test/behavior.clj there are some tests which are now broken. We will replace these tests with some of our own.

Transform functions are pure functions and are therefore very easy to test. We may create some tests for our transform function like the one shown below.

(deftest test-inc-transform
  (is (= (inc-transform nil {msg/type :inc msg/topic [:my-counter]})
         1))
  (is (= (inc-transform 0 {msg/type :inc msg/topic [:my-counter]})
         1))
  (is (= (inc-transform 1 {msg/type :inc msg/topic [:my-counter]})
         2))
  (is (= (inc-transform 1 nil)
         2)))

Notice that this particular transform function does not depend on the input message. We may also want to test the application in general. Before we write this test, let's make a helper function which will extract the data model from an application object.

(defn- data-model [app]
  (-> app :state deref :data-model))

Everything that we need to know about an app is contained in the app object. It is educational to explore its contents.

The test below shows how to create an app and then send it one or more messages. Once the messages are processed we can check the state of the data model. The run-sync! function will ensure that all of the messages have been processed before returning.

(deftest test-app-state
  (let [app (app/build example-app)]
    (is (test/run-sync! app [{msg/type :inc msg/topic [:my-counter]}]
                        :begin :default))
    (is (= (data-model app)
           {:my-counter 1})))
  (let [app (app/build example-app)]
    (is (test/run-sync! app [{msg/type :inc msg/topic [:my-counter]}
                             {msg/type :inc msg/topic [:my-counter]}
                             {msg/type :inc msg/topic [:my-counter]}]
                        :begin :default))
    (is (= (data-model app)
           {:my-counter 3}))))

Running tests

Once we have tests in place we can run them from the command line by running

lein test

or

lein difftest

The second command will show diffs when a test fails.

There are more advanced techniques which can be used to test our applications but for now this is good enough. Notice that even though this is behavior that will run in the browser, we are testing it as plain old Clojure code.

Sharing code

This works because the tutorial-client.behavior namespace is marked as :shared and uses only Clojure code that can be compiled to ClojureScript.

(ns ^:shared tutorial-client.behavior
    (:require [clojure.string :as string]
              [io.pedestal.app.messages :as msg]))

The tag for this step is v2.0.2.

Home | Increment the Counter

Clone this wiki locally