Library for creating matcher combinator to compare nested data structures
current version:
docs: Found on cljdoc
Clojure's built-in data structures get you a long way when trying to codify and solve difficult problems. A solid selection of core functions allow you to easily create and access core data structures. Unfortunately, this flexibility does not extend to testing: a comprehensive yet extensible way to assert that the data fits a particular structure seems to be lacking.
This library addresses this issue by providing composable matcher combinators that can be used as building blocks to effectively test functions that evaluate to nested data-structures.
Midje checkers | Matcher combinators |
---|---|
Midje checkers failure output | Matcher combinators failure output |
---|---|
The matcher-combinators.midje
namespace defines the match
and throws-match
midje-style checkers. These should be used on the right-side of the midje fact
check arrows (=>
)
match
: This checker is used to wrap a matcher-combinator asserts that the provided value satisfies the matcher.throws-match
: This checker wraps a matcher-combinator and optionally a throwable subclass. It asserts that an exception (of the given class) is raised and the ex-data
satisfies the provided matcher.For example:
(require '[midje.sweet :refer :all]
'[matcher-combinators.matchers :as m]
'[matcher-combinators.midje :refer [match]])
(fact "matching a map exactly"
{:a {:bb 1 :cc 2} :d 3} => (match (m/equals {:a (m/embeds {:bb 1}) :d 3}))
;; but when a map isn't immediately wrapped, it is interpreted as an `embeds` matcher
;; so you can write the previous check as:
{:a {:bb 1 :cc 2} :d 3} => (match (m/equals {:a {:bb 1} :d 3})))
(fact "you can assert an exception is thrown "
;; Assert _some_ exception is raised and the ex-data inside satisfies the matcher
(throw (ex-info "foo" {:foo 1 :bar 2})) => (throws-match {:foo 1})
;; Assert _a specific_ exception is raised and the ex-data inside satisfies the matcher
(throw (ex-info "foo" {:foo 1 :bar 2})) => (throws-match ExceptionInfo {:foo 1}))
Note that you can also use the match
checker to match arguments within midje's provided
construct:
(unfinished f)
(fact "using matchers in provided statements"
(f [1 2 3]) => 1
(provided
(f (match [odd? even? odd?])) => 1))
clojure.test
Require the matcher-combinators.test
namespace, which will extend clojure.test
's is
macro to accept the match?
and thrown-match?
directives.
match?
: The first argument should be the matcher-combinator represented the expected value, and the second argument should be the expression being checked.thrown-match?
: The first argument should be a throwable subclass, the second a matcher-combinators, and the third the expression being checked.For example:
(require '[clojure.test :refer :all]
'[matcher-combinators.test] ;; needed for defining `match?`
'[matcher-combinators.matchers :as m])
(deftest basic-sequence-matching
;; by default a sequentials are interpreted as a `equals` matcher
(is (match? [1 odd?] [1 3]))
(is (match? (m/prefix [1 odd?]) [1 1 2 3])))
(defn bang! [] (throw (ex-info "an exception" {:foo 1 :bar 2})))
(deftest exception-matching
(is (thrown-match? ExceptionInfo
{:foo 1}
(bang!))))
If a data-structure isn't wrapped in a specific matcher-combinator the default interpretation is:
embeds
equals
equals
equals
regex
equals
operates over base values, maps, sequences, and sets
expected
.expected
map are equal to the given map's keysexpected
map matches the given map's valuesexpected
sequences's matchers match the given sequence. Similar to midje's (just expected)
expected
set and each matcher is used exactly once.embeds
operates over maps, sequences, and sets
expected
map.expected
sequence. Similar to midje's (contains expected :in-any-order :gaps-ok)
expected
set can be matched with an element in the provided set. There may be more elements in the provided set than there are matchers.prefix
operates over sequences
matches when provided a (ordered) prefix of the expected
sequence. Similar to midje's (contains expected)
in-any-order
operates over sequences
matches when the given a sequence that is the same as the expected
sequence but with elements in a different order. Similar to midje's (just expected :in-any-order)
set-equals
/set-embeds
similar behavior to equals
/embeds
for sets, but allows one to specify the matchers using a sequence so that duplicate matchers are not removed. For example, (equals #{odd? odd?})
becomes (equals #{odd})
, so to get arround this one should use (set-equals [odd? odd])
.
regex
: matches the actual-value-found
when provided an expected-regex
using (re-find expected-regex actual-value-found)
You can extend your data-types to work with matcher-combinators
by implemented the Matcher
protocol.
An example of this in the wild can be seen in the abracad
library here.
The project contains both midje and clojure.test
tests.
Midje is capable of running both types of tests:
lein midje
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close