Skip to content
Ryan Neufeld edited this page Jul 9, 2013 · 7 revisions

To follow along with this section, start with tag v2.0.1.

Most application logic (behavior) code in a pedestal-app application will work with and transform data. This code is part of the common subset of Clojure and ClojureScript. This means that you can test this code in Clojure using the testing tools you're already familiar with.

This section will show you some basic techniques for testing pedestal-app behavior. To keep the tutorial small, the remainder of the tutorial will not cover testing. At the very end, there will be one more section showing more advanced testing techniques.

In this section you will be introduced to the following pedestal-app concepts:

  • Testing behavior code
  • Sharing Clojure and ClojureScript code

Testing behavior

The application currently has some very simple behavior which is easy to confirm 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. In this section you will replace these tests with some of your own.

Transform functions are pure functions and are therefore very easy to test.

(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.

You may also want to test the application in general. The application object contains a lot of useful information which can be inspected. The function below will extract the current value of data model from the application.

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

The test below shows how to create an app and then send it one or more messages. Once the messages are processed you 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}))))

This test also shows how a dataflow definition becomes an application object that can be interacted with.

As stated above, these are simple testing methods; a later section will cover more advanced testing techniques.

Running tests

Once you have tests in place, you can run them from the command line with

lein test

or

lein difftest

The second command will show diffs when a test fails.

Sharing code

You may be wondering how we have been able to run this namespace in the browser and then test it in Clojure. The tutorial-client.behavior namespace is Clojure code. The file extension is .clj. The only thing that is special about this namespace is that it is marked as being :shared. When compilation occurs, any Clojure namespaces marked :shared will also be compiled to ClojureScript.

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

For now, these files must contain the common subset of Clojure and ClojureScript. A new feature of Clojure 1.6, feature expressions, will allow us to break free from this restriction.

The tag for this section is v2.0.2.

Home | Increment the Counter