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

New gen-let experimental syntax #449

Closed rafaeldff closed 5 years ago

rafaeldff commented 6 years ago

The experimental (for-all) macro allows for declaring generators that are easily integrated into midje tests. It does not, however, allow for composing generators. In this pull-request we introduce a new macro - (gen-let) - that desugars to a chain of (gen/bind)s, in a manner similar to clojure.test.check.generators/let. Eg:

 (fact "composing generators"
  (gen-let [i  gen/s-pos-int
            is (gen/vector gen/int i)
            e  (gen/elements is)]
    (count is) => i
    (some #{e} is) => e)) 

The gen-let macro also supports binding intermediate computations with the :let keyword (syntax loosely inspired by clojure's for macro):

 (fact "a :let block can be in the middle of gen-let bindings"
  (gen-let [i  (gen/choose 0 9)
            :let [s  (str i)
                  s2 (str s s)]
            xs (gen/elements [s s2])]
    (->> xs seq (map #(Character/getNumericValue %)) (some #{i})) => i)) 

The for-all macro is still useful because, even though we could express every test with gen-let, the bind based desugaring is less efficient and less amenable to test case shrinking. We have ideas about a future unification of the two macros, relying on more sophisticated static analysis, but it is not a trivial effort, and there are real use cases that could benefit from the proposed gen-let abstraction.