Fork me on GitHub

Regarding the testing discussion from yesterday, for some time I’ve been very partial to the generative testing idea of pairwise/all-pairs testing. Which strikes me as a very principled approach to reducing the state space under test to something that is both tractable and “more likely” to discover bugs. The idea goes that most bugs occur at the interaction between two parameters. So roughly; you then model your test space into categories for each distinct kind of value for each parameter, and then ensure each test tests a distinct pairing across those parameters. It’s hard to write a good accurate short description; so I’d encourage you to look at it… but the net result is if your total state space combinatorially had say 5000 parameterisations, you’d likely need just a handful of well chosen parameterisations to effectively test that input space. I often think about trying to combine it in design of clojure.spec/test.check test models. So you’d effectively bucket the generators to generate random values that share each “interesting property” (and randomise the rest), and then pairwise test those in your fdef; instead of randomly test them.


My thoery being you’d get much quicker generative test runs; which tested the pairwise space exhaustively; but also randomly explored the test space you didn’t explicitly think of.


Whenever I’ve googled this though; I’ve never seen anyone talk about combining these techniques.


The effectiveness and efficiency of the technique is well summarised in the snippets on this page:


Mornin' All 🙂


Where do people normally put their test resources, like test files etc... I notice that the layout is different from a maven-ish type of layout. i.e., a top level src and test and resources folder, rather than src/main/resources and src/test/resources. Would src/resources and test/resources be the way, or resources/test?


I’d normally separate dev and prod. And put test stuff with dev. e.g. /dev/resources /dev/src


I’d recommend having test stuff available at the REPL too, so in your dev env.


this is how leiningen profiles work. :dev is available when you lein test for example. Though I always try and support this in tools.deps projects too. The :test profile in lein is only sourced for running lein test, so not in the REPL; so it’s seldom used properly — though often misused by people that don’t understand the design.


Though I’m not arguing against putting it in /test/resources (I’ve done that in some projects too) just that you should ensure that is on the classpath in dev too.


thank you for your feedback 🙂 In deps.edn, I've created a local alias (I prefer local over dev, as local is your local machine, whereas dev is normally (for us anyway) the first environment that code gets deployed to)


I have then added in an extra-paths configuration. 🙂


Cool :thumbsup: . I definitely agree you should also have features in your projects for local overrides. Some of our projects have quite a sophisticated set of overrides, as we have some multi-tenant apps; that have a base setup, then customer specific classpaths and overrides, then a shared dev set of overrides (committed into the project), including a dev.clj namespace of functions for use in dev followed finally by local overrides, and even a .gitignored local.clj is loaded in dev; which is a transient place to persist functions or calls to things specific to your workflow in that project… e.g. you might put a call to s/instrument in there to stub out some remote calls and return generated data with some :gen overrides etc… which can be useful for e.g. spot checking UI components display and wrap appropriately with crazy data in etc… Finally there is the option for customer specific production overrides, and a final option of supplying an edn file of overrides on the command line in prod. Also overrides can come from env vars; though that is usually abstracted out through integrant/aero. The prod overrides don’t usually get used much, as we tend to configure the base config to be production like, and override it to be dev - but they’re a safety net. Likewise the option of supplying them on a command line is mainly for the hotfix usecase (as we tend to uberjar production jars), or for debugging a production jar.


I don’t have a :local alias though, I instead apply any individual ones I need… though some such as my cider setup are glommed together with a few other things… they’re kinda implicitly local, because they’re in my ~/.clojure/deps.edn


Clojure related question... Is the a more succinct way to achieve this?

(def v [{:id 1 :value "foo"}{:id 2 :value "bar"}])
(mapv #(assoc {} :value (:value %)) v)
;; => [{:value "foo"} {:value "bar"}]




@dharrigan I would put them in test/resources as I suspect they won't be packed in the uberjar, but haven't tried this myself so please check.


Was good to visit the #juxt London office today. There were hugs


@otfrom gave a double air lifted hug. Strong man.

parrot 8
mario-star 8
💪 8

Clojure community is good at (( hugs )) 😄