Expectations

a minimalist's unit testing framework

This project is maintained by seancorfield and jaycfields

expectations

adding signal, removing noise

Advanced Usage

In the last section I gave examples of how to use expectations to test for equality. This section focus on non-equality expectations that are also available.

Regex
expectations allows you to use a regex as your expected value, and if the 'actual' string matches that regex the expectation passes. The following example shows both the successful and failing expectations that use regexes.
(expect #"in 14" "in 1400 and 92")

jfields$ lein expectations
Ran 1 tests containing 1 assertions in 4 msecs
0 failures, 0 errors.

(expect #"in 14" "in 1300 and 92")

jfields$ lein expectations
failure in (core.clj:17) : sample.test.core
           (expect in 14 in 1300 and 92)
           regex #"in 14" not found in "in 1300 and 92"
Ran 1 tests containing 1 assertions in 5 msecs
1 failures, 0 errors.
As you can see from the previous example, writing an expectation using a regex is syntactically the same as writing an equality expectation - and this is true for all of the non-equality expectations. In expectations there is only one syntax for expect - it's always (expect expected actual).

Almost Equal
When you provide a numeric expected value, expectations will check that it is equal to the actual value. That's fine for integer values but not good for floating point values, so expectations provides a predicate that lets you expect "almost equal" values:
(expect (approximately 0.333) (/ 1 3)) ;; succeeds
(expect (approximately 0.333 0.001) (/ 1 3)) ;; equivalent to this
You can specify a delta value for how close the actual value must be. As shown above, the default is 0.001 and the test is equivalent to:
(expect true (<= 0.332 (/ 1 3) 0.334))

Functionally Equivalent
Sometimes your expected and actual values are computed via functions from the same underlying value. If you're trying to do this with from-each, it can be a bit awkward as you need both the underlying item from the sequence (to compute the expected value) as well as the computed actual value. The functionally predicate is intended to help with that:
;; compares the results of calling fn-1 and fn-2 on values from 0..99:
(expect (functionally fn-1 fn-2)
        (from-each [a (range 100)]
          a))
The default failure message is "not functionally equivalent" but you can provide your own "difference" function that accepts the computed results from each function (effectively the expected value and the actual value) and returns a string explaining how they differ. For string results, you can use strings-difference which is what Expectations uses internally when explaining how expected and actual strings differ.
Testing for a certain type
I basically never write tests that verify the result of a function is a certain type. However, for the once in a blue moon case where that's what I need, expectations allows me to verify that the result of a function call is a certain type simply by using that type as the expected value. The example below shows the successful and failing examples of testing that the actual is an instance of the expected type.
(expect String "in 1300 and 92")

jfields$ lein expectations
Ran 1 tests containing 1 assertions in 6 msecs
0 failures, 0 errors.

(expect Integer "in 1300 and 92")

jfields$ lein expectations
failure in (core.clj:17) : sample.test.core
           (expect Integer in 1300 and 92)
           in 1300 and 92 is not an instance of class java.lang.Integer
Ran 1 tests containing 1 assertions in 5 msecs
1 failures, 0 errors.
Expected Exceptions
Expected exceptions are another test that I rarely write; however, when I find myself in need - expectations has me covered.
(expect ArithmeticException (/ 12 0))

jfields$ lein expectations
Ran 1 tests containing 1 assertions in 6 msecs
0 failures, 0 errors.

(expect ClassCastException (/12 0))

jfields$ lein expectations
failure in (core.clj:19) : sample.test.core
           (expect ClassCastException (/ 12 0))
           (/ 12 0) did not throw ClassCastException
Ran 1 tests containing 1 assertions in 4 msecs
1 failures, 0 errors.
There's another non-equality expectation that I do use fairly often - an expectation where the 'expected' value is a function. The following simple examples demonstrate that if you pass a function as the first argument to expect it will be called with the 'actual' value and it will pass or fail based on what the function returns. (truthy results pass, falsey results fail).
(expect nil? nil)
(expect true? true)
(expect false? true)

jfields$ lein expectations
failure in (core.clj:19) : sample.test.core
           (expect false? true)
           true is not false?
Ran 3 tests containing 3 assertions in 4 msecs
1 failures, 0 errors.
These are the majority of the non-equality expectations; however, there is one remaining non-equality expectation - in. Using 'in' is fairly straightforward, but since it has examples for vectors, sets, and maps I felt it deserved it's own section - which is available here.