Fork me on GitHub
#beginners
<
2019-07-05
>
nate_clojurians02:07:11

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

seancorfield02:07:22

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

seancorfield02:07:06

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

dharrigan09:07:34

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?

alexmiller11:07:49

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

dharrigan12:07:42

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

alexmiller13:07:42

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

dharrigan14:07:15

thank you πŸ™‚

noisesmith09:07:24

@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

dharrigan09:07:53

ooh, that is dangerous

dharrigan09:07:36

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!

noisesmith09:07:30

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

jaihindhreddy13:07:45

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.

noisesmith13:07:05

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

noisesmith13:07:51

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

johnjelinek15:07:59

@seancorfield: thanks for making this https://youtu.be/CWjUccpFvrg

seancorfield15:07:32

@johnjelinek Glad you found it useful!

johnjelinek15:07:21

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

seancorfield17:07:13

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

andrea.imparato17:07:06

πŸ‘‹ anybody here use compojure-api? I'm trying to run https://github.com/metosin/compojure-api-examples

andrea.imparato17:07:12

^ this is what I get

hiredman17:07:28

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

seancorfield17:07:58

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

hiredman17:07:50

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?

seancorfield17:07:20

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...

dpsutton17:07:22

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?

seancorfield17:07:42

^ @andrea.imparato There you go!

dpsutton17:07:04

0.12.5 it seems

seancorfield17:07:53

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

seancorfield17:07:15

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

andrea.imparato17:07:06

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

dharrigan19:07:30

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

dharrigan19:07:45

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

nate_clojurians19:07:35

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

nate_clojurians19:07:57

I have this right now

nate_clojurians19:07:09

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

nate_clojurians19: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

alexmiller19:07:49

either is the same result

alexmiller19:07:16

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

alexmiller19:07:36

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

nate_clojurians19:07:07

ha, yeah, definitely

nate_clojurians19:07:51

so I have this for specs for this structure

nate_clojurians19:07:30

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

nate_clojurians19: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

nate_clojurians19:07:12

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

nate_clojurians19:07:40

maybe a predicate on the maze itself?

nate_clojurians19:07:53

that seems good?

nate_clojurians20:07:24

whoops, should be keys not vals

nate_clojurians20:07:54

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

nate_clojurians20:07:45

oh, I know what it is. gah, duplicates

nate_clojurians21:07:38

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

dpsutton21:07:11

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

seancorfield21:07:16

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

nate_clojurians21: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)))))

nate_clojurians21: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))))

nate_clojurians21:07:20

but that kind of sucks

nate_clojurians21:07:53

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

seancorfield21:07:18

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

seancorfield21:07:08

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

FAIL in () (NO_SOURCE_FILE:1)
expected: (= "Success!\n" (s/explain-str even? 43))
  actual: (not (= "Success!\n" "43 - failed: even?\n"))
false
user=> 

nate_clojurians21:07:38

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

seancorfield21:07:25

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

nate_clojurians21: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

nate_clojurians21:07:54

ahhh interesting

seancorfield21:07:21

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

nate_clojurians21:07:42

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

seancorfield21:07:01

Ah, that's a shame πŸ™‚

nate_clojurians21:07:47

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

darioszr21:07:15

Moin, I'm trying to import a java lib from maven with leinigen. The library is this one: https://github.com/prometheus/client_java

nate_clojurians21:07:16

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

darioszr21:07:50

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

darioszr21:07:17

[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.. 😁

seancorfield22:07:26

@nate_clojurians 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]])
nil
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/def ::foo even?)
:user/foo
user=> (expect ::foo 42)
true
user=> (expect ::foo 43)

FAIL in () (NO_SOURCE_FILE:1)
43 - failed: even? spec: :user/foo

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

seancorfield22:07:51

You can use expect in place of is inside deftest.

nate_clojurians22:07:58

ahhh that's nice

nate_clojurians22: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

nate_clojurians22:07:48

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

seancorfield22:07:09

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

seancorfield22:07:09

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

seancorfield22:07:06

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).

nate_clojurians22:07:33

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

seancorfield22:07:50

It runs a clojure.test-compatible suite.

seancorfield22:07:05

There are lots of test runners out there.

seancorfield22:07:50

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

seancorfield22:07:10

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

seancorfield22:07:36

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

seancorfield22:07:39

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