I applaud everyone who has volunteered to help write tests for Clojure. A good test suite not only catches problems but also helps beginners learn the language.
Regarding the proposal in the previous post, I think we should be careful about drawing inferences between the use of random values and the resulting quality of the tests. In my experience, test developers often use random values when fixed, hard-coded values work just as well. I think it is more important to look for (and test) edge conditions than it is to pull values out of a bag. I also think using random values makes tests less reproducible. That's not to say there is never a time for randomization. I just think it can make tests unnecessarily complicated. Bill On Oct 26, 12:47 pm, Meikel Brandmeyer <[EMAIL PROTECTED]> wrote: > Dear Clojurians, > > Stuart brought up the idea of implementing a QuickCheck clone > for Clojure. I think that this is a good idea, since it provides > a much better coverage of possible inputs. I gave it some thought > this weekend and the following is, what I came up with. There > are some specifics of the API which I will ignore in the beginning. > They will be explained later on. > > Comments, thoughts, improvements appreciated. > > ClojureCheck generates random input samples and feeds them to > the functions under test. The generation is done via generation > functions, which are combined via so-called combinators to more > complex generators. > > The core is the function arbitrary. It generates the random values > for a given type. As Stuart already suggested, I think a multi > method is the best way to model this. > > (defmulti arbitrary (fn [x & _] (if (vector? x) (first x) x))) > > The first value is itself normally unused, since it normally > only gives the type on which we dispatch. So we can for example > define a generator for integers. > > (defmethod arbitrary Integer > [_ size] > (int (Math/round (* size (.nextDouble *prng*))))) > > (arbitrary Integer 100) > > To use a generator one uses for-all. > > (for-all [x Integer > y Integer] > (test-is/is (= (+ x y) (+ y x)))) > > This code actually cannot be used directly. You may have noticed > the unexplained size parameter in the arbitrary call. This is a > special parameters passed to the generators to allow a scaling > of the test samples. So a generator of lists may start with short > lists and may generate longer and longer lists as the test iterates. > To hide this from the developer for-all actually returns a generator > itself, ie. a function which accepts the size parameter and passes > it on the generators in the binding form. So to run actually the > tests, one uses the property function. > > (property > (for-all [x Integer > y Integer] > (test-is/is (= (+ x y) (+ y x))))) > > This runs the tests for certain (configurable) number of iterations. > Binding x and y to random integers each time. > > But sometimes one wants to pass parameters to the generators. I > thought about the way eg. require does this: (require [foo :as bar]). > So I thought one could do this by specifying a vector in the binding > form. > > (for-all [x [:IntegerRange 100 1000]] > (test-something-with x)) > > (defmethod arbitrary :IntegerRange > [[_ mn mx] _] > (int (Math/round (+ mn (* (- mx mn) (.nextDouble *prng*)))))) > > The environment like the random number generator, the number of > test iterations etc. would be configurable at runtime. > > A first prototype looks promising. But before I run to far in the > wrong direction, I'd like to ask for comments on the API so far. > Especially things like passing arguments via a vector... > > Sincerely > Meikel > > smime.p7s > 5KViewDownload --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---