This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-07-25
Channels
- # announcements (1)
- # babashka (15)
- # biff (15)
- # calva (9)
- # cherry (18)
- # cider (43)
- # cljs-dev (1)
- # cljsrn (10)
- # clojure (14)
- # clojure-europe (47)
- # clojurescript (29)
- # clr (5)
- # conjure (1)
- # core-logic (17)
- # datomic (8)
- # emacs (22)
- # fulcro (3)
- # gratitude (1)
- # hoplon (23)
- # humor (1)
- # hyperfiddle (34)
- # jobs (1)
- # kaocha (1)
- # malli (3)
- # nrepl (4)
- # off-topic (18)
- # pathom (12)
- # pedestal (1)
- # polylith (1)
- # portal (17)
- # practicalli (1)
- # re-frame (19)
- # reitit (8)
- # releases (1)
- # rewrite-clj (4)
- # shadow-cljs (15)
- # sql (23)
- # tools-build (4)
måning
Good morning!
I have this recurring feeling that unit tests are underutilised. Often, when our non-technical people ask about some functionality that is in the unit tests, we've been able to say with pride and joy that "That functionality is ensured and documented in our unit tests." Which is great for developers, but the non-techies never read them, no matter how well written 🙂 And, often, even developers fail to discover our brilliant tests. I've been wondering if there's a way to bring the tests more into the light. Maybe some kind of literal programming via tests? Generating more non-technical documentation via tests? There must be existing work in this regard.
I wanted to try this for some time https://github.com/matthewdowney/rich-comment-tests
https://clojuredocs.org/clojure.core/test#example-542692cac026201cdc326b8a you can write unit tests right in the function's metadata

I think part of the problem is that most unit tests are poor examples, and what I really want is an example.
@U0525KG62 Can you expand on that? I find that, for pure functions, it's easy to write unit tests as examples.
it is easy to write them as examples, it is just that most people don't so it isn't necessarily somewhere I go to look for examples. I really like the way the tablecloth examples are done: https://scicloj.github.io/tablecloth/
@U04V4KLKC how did I not know that! I need to refac some stuff. Maybe not shove all tests in there, but definitely some trivial ones that I normally put in the description.
@U0525KG62 This is kind of what I was referring to, making it more accessible as a notebook or whatever it's called. It seems to me that, with some extra forms or metadata and some test-to-book converter, you should be able to write valid Clojure tests that can also generate the above kind of presentation of what the tests document.
And your point about not going to the tests because you don't expect stuff to be there is part of what I'm regretful about, and part of my motivation to do something extra 🙂
I think this is the kind of thing clerk (and other #C02V9TL2G3V people) are working on
Because we do have great examples in our code base
@U4GEXTNGZ interesting rewriting 🙂
worth pointing to those examples from some docs then (and more than just "our tests are great")
btw, clojure-lsp is capable to tell in which tests (defined using deftest
) some particular function is being used. Note 16 tests
mark
this makes it easier to jump to examples of usage
Very nice 🤓
Being a bit negative here, I think you’re falling in the Cucumber trap, ie spending a lot of energy on writing tests in a human readable form under the hopes that non-tech people will ever read the tests of their own free will. Having said that, I think there is immense value in maintaining a test code base which lets you write tests which clearly communicates what you’re testing and which lets you hide the accidental complexity. Looking through our codebase I thought we’d have better examples, but have a look at:
(deftest connected-references-test
(ardoq/as :org-admin
(let [{:keys [component-1 component-2
reference-1 reference-2]} (api/create-complete-dataset)
scenario (:scenario (api/create-full-scenario {:name "lol" :componentIds [] :referenceIds []}))
scope-id (:scopeId scenario)]
(api/add-to-scenario (core/id scenario) [(core/id component-1)])
(let [{:keys [referencesToScope] :as s} (api/connected-references scope-id [(core/id component-2)])]
(is (= #{(core/id reference-1)
(core/id reference-2)}
(set (map core/id referencesToScope))))))))
While a product owner or enduser can’t really read this, as a dev, you can fairly easily translate this to human language:
As an org admin I create a bunch of components and references, then I create an empty scenario and I add a component to that scenario.
We should then (because of the shape of the dataset) get back that component-2
is connected to the scenario via reference-1
and reference-2
Notice that these are not unit tests, but integration tests that go through our rest api, down to the database and back.
Also note that running this tests leads to 88 assertions being asserted even though we only have one explicit assertion in this test.
an intentfully-crafted are
is essentially a table, could be as well presented as a spreadsheet to the business people
An example:
https://github.com/clojure-emacs/orchard/blob/d04e418301097f4ba297874b8ec9045a2af04073/test/orchard/indent_test.clj#L38-L53
...it might seem excessively technical but in reality it's just data, anyone can understand that 🙂
Many things can be expressed under are
. Normally Clojure devs think of it as sugar for a simple is = x y
, but one can encode more exhaustive, multi-columnar truth tables
it's not too crazy that for a few are
s in your codebase, you could declare them as deftest ^:export foo-test
then you'd continuously export these truth tables somewhere that anyone could view
this is opposed to other technical knowledge which can only be exported in a one-off fashion, like Slack's famous notification logic
I really liked fitnesse for presentable acceptance tests. A 'modern' implementation of the concept would be nice.
@U04V5VAUN I'm with you. I've seen beautiful technical documentation be ignored by business people - and other groups - many a time. Cucumber seems nice on the surface, but I don't really know if it's worth it to add another layer of indirection, seems like a lot of extra work. I like the succinctness of Clojure's unit tests, plus the added extra explanations in testing
strings.
As for your example, I agree that your code is very readable, and that's generally a thing to strive for; ensuring that the next developer understands what's going on.
I've seen implicit assertions in our code base as well, and while I understand the motivation - "We want to ensure that these things are true for all operations of this kind, so we'll assert them implicitly in every test that runs this kind of operation", I guess - I think it can be a bit confusing when the tests fail, and also when writing and rewriting tests in an ns that uses this kind of framework. I generally prefer things to be more explicit, and for the test to be as self-contained as possible. But repeating yourself again and again by pasting the same assertions in loads of tests also feels silly, so I suppose there's a place for implicit, abstracted-away assertions 🙂 And I guess that the farther you move from pure unit tests for small components and into integration tests, the more relevant those kind of abstractions become, which is what your example shows.
@U45T93RA6 I think I've used are
once and I keep forgetting about it!
writes note to read up on it and think about relevant places of usage
Clojure joke of the day: you can take a horse to paredit but you can't make it slurp

You’ll never know, I have seen horses spit in front of the pharmacy
(Just comes to mind, that this is probably a German proverb which is unknown to the rest of the world)
Not with that attitude - but this .. https://www.youtube.com/watch?v=Qc8rsnRC1EU
I refuse to forget all the junk on the internet - that's why my mind has no space left for useful crap