marick / Midje

Midje provides a migration path from clojure.test to a more flexible, readable, abstract, and gracious style of testing
MIT License
1.69k stars 129 forks source link

How to check a nested map with `roughly` #418

Closed viebel closed 6 years ago

viebel commented 7 years ago

How can we check a nested map with roughly

This doesn't work:

(fact {:a  {:b 1}} => (just {:a {:b (roughly 1.0)}}))

But this works:

(fact {:a  {:b 1}} => (just {:a (just {:b (roughly 1.0)})}))

Is there a simpler way?

philomates commented 7 years ago

This question is sorta similar to https://github.com/marick/Midje/issues/405#issue-266243572; wanted to link them so that the context from the two issues can be shared.

As far as I know, wrapping each level with a check is the way to do it currently.

That said, a colleague and I are working on building a matcher-combinator library that can be used with midje and will do this wrapping automatically so that you can write tests like (fact {:a {:b 1}} => (embeds {:a {:b (roughly 1.0)}})

Since this has been requested a bunch and we actually use a similar, but hacky approach a lot within our organization, this is going to be the next midje feature I prioritize :)

marick commented 7 years ago

That will be great.

philomates commented 6 years ago

To follow up on this, we've released a new library for checking nested data-structures that attempts to solve the problem described here: https://github.com/nubank/matcher-combinators

Using it with midje, you can write

(require '[midje.sweet :refer :all]
         '[matcher-combinators.matchers :refer [equals embeds]]
         '[matcher-combinators.midje :refer [match]])
(fact
  {:a {:b 1}} => (match {:a {:b (roughly 1.0)}}))

which is equivalent to

(fact
  {:a {:b 1}} => (contains {:a (contains {:b (roughly 1.0)})}))

And to do exactly

(fact 
  {:a {:b 1}} => (just {:a (just {:b (roughly 1.0)})}))

with matcher-combinators you still need to wrap the nested maps with the strict equals matcher because the default matcher for maps is a looser embeds (similar to midje's contains)

(fact
  {:a {:b 1}} => (match (equals {:a (equals {:b (roughly 1.0)})})))

matcher-combinators also give you nice diff messages when there are mismatches in results and can also be used in other test frameworks.

philomates commented 6 years ago

closing this out given that the matcher-combinators library solves the issue and is integrated with midje.

philomates commented 6 years ago

Sorry, I closed it before offering a satisfactory solution to your exact problem via matcher-combinators. Good news is that I have a PR open that implements what you are looking for: https://github.com/nubank/matcher-combinators/pull/29

When that gets merged/released you can do something like

(fact
  {:a {:b 1}} => (matcher-combinators.midje/match-equals {:a {:b (roughly 0.95)}}))

or even define your own matcher like this

(midje.checking.checkers.defining/defchecker my-matcher [matcher]
  (let [delta 0.1]
    (matcher-combinators.midje/match-with
      {:number (fn [exp] (matcher-combinators.core/->Roughly delta exp))
       :map    (fn [exp] (matcher-combinators.core/->EqualsMap exp))}
      matcher)))
;; ---
(fact
  {:a {:b 1}} => (my-matcher {:a {:b 0.95}}))
viebel commented 6 years ago

thanks for the updtae @phillipm