Fork me on GitHub
Cora (she/her)02:07:11

is there a way to use a clojure spec for assertions in tests?


@corasaurus-hex I would do something like (is (s/valid? ::some-spec a-valid) (s/explain ::some-spec a-valid)) -- untested but should be close.


assert throws an exception which isn't very useful in a test.


To clarify, I see that creating a def inside a defn is considered bad practice, is this because that def will create a new global binding, i.e., that bound var could be accessed anywhere in the namespace? The proper approach (I know this, I'm just clarifying my thoughts) is to use let which creates a new lexically scoped var, that once the let is done, the var is unbound?


let doesn’t create a var at all, just a local binding


thank you Alex for clarifying, I guess I was trying to find the right word, but now I have it! πŸ™‚


local bindings are also much lighter weight in terms of the compiler and compiled code as well (all local, not global)


thank you πŸ™‚


@dharrigan not only is it accessible anywhere, but if your function is run concurrently, both instances are mutating the same shared value, a classic source of errors


ooh, that is dangerous


thanks. I was asked by a colleague why not do as I explaining some clojure to him, I think I did okay, but didn't mention about the concurrency issue!


one of the best things about clojure is that if we write normal code, it's automatically thread safe, but that means our definition of "normal code" can't include def inside defn :D


I've been using agents to perform http requests, and I'm wondering how to respect 429s and rate limit myself. Is that possible with vanilla agents, or do I need something else? I can tolerate some (< 15 %) requests not going.


since agent actions are serialized, you could have the agent send itself #(Thread/sleep n) followed by re-sending the same function it was executing


any new actions would get queued up to run after the sleep and the retry are done


@johnjelinek Glad you found it useful!


Indeed! I've been using vscode instead of atom, but there's a lot I want to copy from your video.


@johnjelinek Feel free to reach out with any questions you might have about the workflow etc.

πŸ‘ 4
Andrea Imparato17:07:06

πŸ‘‹ anybody here use compojure-api? I'm trying to run

Andrea Imparato17:07:12

^ this is what I get


the example repo is really old, and likely using an old broken version of unify


Yeah, this came up a few days back -- let me search Zulip for the info...


if you run it with the versions as specified in the repo I would expect it to work

Andrea Imparato17:07:39

how is compojure-api for building rest api?

Andrea Imparato08:07:52

thank you very much very much appreciated (as usual :))

Andrea Imparato17:07:48

i mean, is it good or bad?


Looks like the old version of the lein-ring plugin is probably the issue here -- based on the discussion mirrored to Zulip from February, but I thought it came up more recently...


this came up for me twice this week and was related to an outdated lein-ring plugin. i think you want 0.5.12 maybe?


0.12.5 it seems


compojure-api is fine for building REST APIs. We use plain Compojure, and JSON middleware at work for our REST APIs.


(so I should probably say "our REST-like APIs" πŸ™‚ )

Andrea Imparato17:07:06

eheh πŸ‘ yeah I want to use it for a pet project just to practice a bit with web development πŸ™‚

clj 4
πŸ•ΈοΈ 4

I've had nice success with clj-http-rest


oh, that's for client, not as a server

Cora (she/her)19:07:35

what's a good strategy for naming tests in deftest?

Cora (she/her)19:07:57

I have this right now

Cora (she/her)19:07:09

where the deftest symbol is the same as the function being tested

Cora (she/her)19:07:41

I guess I'm not understanding the naming of tests here, and why it's not just using testing at the top level


either is the same result


I'd say, don't be afraid of using words in test names :) like test->maze-constructor-function is perfectly good too


6 months later when it fails and prints that in your console, it may be helpful :)

Cora (she/her)19:07:07

ha, yeah, definitely

Cora (she/her)19:07:51

so I have this for specs for this structure

Cora (she/her)19:07:30

is there a way to link the valid coordinates in the :cells map to the width and height?

Cora (she/her)19:07:44

the valid value for a coordinate is this structure with values within these ranges: [(range 1 (inc width)) (range 1 (inc height))] but I'm not quite sure how to express that

Cora (she/her)19:07:12

it's not strictly needed but it would mean fewer tests needed

Cora (she/her)19:07:40

maybe a predicate on the maze itself?

Cora (she/her)19:07:53

that seems good?

Cora (she/her)20:07:24

whoops, should be keys not vals

Cora (she/her)20:07:54

well, no, it's still busted. ugh. what.

Cora (she/her)20:07:45

oh, I know what it is. gah, duplicates

Cora (she/her)21:07:38

is there a way to make the message of an is be lazily evaluated?


what's your issue? how is laziness vs strictness hurting you?


@corasaurus-hex Do you mean that you only want the expression in the "message" position to be evaluated if the test fails?

Cora (she/her)21:07:54

in this case it's like

(deftest ->maze
  (testing "creates a valid maze"
    (is (s/valid? :grid/maze (g/->maze 2 3))
        (s/explain-str :grid/maze (g/->maze 2 3)))))

Cora (she/her)21:07:17

and I can change it to this to avoid the double evaluation:

(deftest ->maze
  (testing "creates a valid maze"
    (let [msg (s/explain-str :grid/maze (g/->maze 2 3))]
      (is (= "Success!\n" msg) msg))))

Cora (she/her)21:07:20

but that kind of sucks

Cora (she/her)21:07:53

it's not really a problem, it's cheap to do in this case, but I'm trying to learn πŸ™‚


(is (= "Success!\n" (s/explain-str :grid/maze (g/->maze 2 3))))


user=> (t/is (= "Success!\n" (s/explain-str even? 42)))
user=> (t/is (= "Success!\n" (s/explain-str even? 43)))

expected: (= "Success!\n" (s/explain-str even? 43))
  actual: (not (= "Success!\n" "43 - failed: even?\n"))

Cora (she/her)21:07:38

right, that's doable, but is there a way to make the message lazily evaluated?


(reify Object (toString [_] (s/explain-str even? 43))) -- but the resulting message is wrapped in #object[ ... ]

Cora (she/her)21:07:33

I'm not really too concerned with how I solve this, just trying to learn if there's a way to lazily evaluate a string

Cora (she/her)21:07:54

ahhh interesting


Actually, is is a macro so I suspect it doesn't evaluate the msg form unless the test fails... let me verify that...

Cora (she/her)21:07:42

it does evaluate it, because I was using s/explain before and it was printing out "Success!"


Ah, that's a shame πŸ™‚

Cora (she/her)21:07:47

yeah, it seems like a good place to avoid having it immediately evaluated

βœ”οΈ 4

Moin, I'm trying to import a java lib from maven with leinigen. The library is this one:

Cora (she/her)21:07:16

like a logger macro that doesn't evaluate messages when the log level isn't one that will log


[io.prometheus/simpleclient "version"] should be ok right?


[io.prometheus/simpleclient "0.6.0"] ok so worked.. First time I import a java lib 😁 I did a typo before that's why didn't worked.. 😁


@corasaurus-hex Something to consider if you want to test with specs is to use expectations/clojure-test which provides more expressive tests. For example:

(! 537)-> clj -Sdeps '{:deps {expectations/clojure-test {:mvn/version "RELEASE"}}}'
Clojure 1.10.1
user=> (require '[expectations.clojure.test :refer [expect]])
user=> (require '[clojure.spec.alpha :as s])
user=> (s/def ::foo even?)
user=> (expect ::foo 42)
user=> (expect ::foo 43)

43 - failed: even? spec: :user/foo

expected: (=? :user/foo 43)
  actual: (not (=? :user/foo 43))

clj 4

You can use expect in place of is inside deftest.

Cora (she/her)22:07:58

ahhh that's nice

Cora (she/her)22:07:44

it's just this one instance right now so I'll forgo the library but I'll star that one for the future

Cora (she/her)22:07:48

I see you there, going to guess that's the case πŸ™‚


I started using Expectations years ago, after seeing it presented at Clojure/West. Eventually (as with so many libraries!) I ended up taking over as maintainer. But it always bothered me that the core Expectations library is not compatible with clojure.test. That's what I wrote expectations/clojure-test


It's basically the syntax from the original Expectations library (that first link), transplanted into the clojure.test environment.


We use it for almost everything at work. Works with Cognitect's test-runner, for example. Works with Cursive as well I believe (which does some fancy stuff with test failures).

Cora (she/her)22:07:33

cognitect's test runner isn't clojure.test?


It runs a clojure.test-compatible suite.


There are lots of test runners out there.


clojure.test needs a test runner in order for you to run tests from the command-line.


lein test is another test runner (again, expecting something clojure.test-compatible).


(CIDER is also a test runner, among other things)


There's an #expectations channel if you get deeper into that library and have questions. I'll notice them more easily there.

πŸ‘ 4