clojure.test.check is a library for testing your code with lots of random data. You first specify certain properties of your program, and
test.check will generate data and verify that the properties hold. Let’s see how that looks in practice.
First take a regular unit test. This one tests the
normalize function from
lambdaisland.uri by feeding it a string, and checking the result.
(:require [lambdaisland.uri :as uri]
[lambdaisland.uri.normalize :as n]
[clojure.test :refer [deftest testing is are]]))
(is (= (str (n/normalize (uri/uri "http://foo.bar?q=💃")))
That’s a useful test, but that test alone isn’t enough to inspire confidence, so you go on and add more and more of these test cases, each time coming up with some data that tests a specific aspect of the implementation. This works alright, but coming up with good test cases is limited by your patience and imagination.
It’s not just that you won’t come up with enough test cases, it’s also that you will tend to test “reasonable” data, missing many edge cases.
(are [in out] (= (str (n/normalize (uri/uri in))) out)
Wouldn’t it be great if you could generate test cases on the fly, testing them by the hundreds or thousands?