This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-06-26
Channels
- # admin-announcements (3)
- # beginners (44)
- # boot (48)
- # cljs-dev (2)
- # cljsjs (14)
- # cljsrn (2)
- # clojure (32)
- # clojure-android (1)
- # clojure-nl (1)
- # clojure-portugal (1)
- # clojure-russia (7)
- # clojure-spec (51)
- # clojure-uk (21)
- # clojurescript (9)
- # component (2)
- # cursive (4)
- # emacs (5)
- # funcool (1)
- # hispano (3)
- # hoplon (10)
- # immutant (14)
- # jobs (1)
- # jobs-discuss (4)
- # off-topic (15)
- # om (1)
- # onyx (1)
- # planck (36)
- # re-frame (2)
- # reagent (25)
- # spacemacs (2)
- # spirituality-ethics (10)
- # untangled (2)
- # vim (8)
- # yada (1)
hey all, I've been trying to get my head around testing in lisp (I know some Clojure but code predominantly in Racket) after coming from a Ruby background - in particular mocking your functions. In Ruby, it's easy to use dependency injection + mock objects to make sure arguments are being passed around correctly. This makes testing easy to reason about and keeps your tests short and compact. I am not sure how is the best practice for doing this when you're coding functionally. If you have a function with inner functions do you always define them externally so you can test them? Do you have opinions on if the function is only used once? As for mocking stateful functions, Racket doesn't have much by way of mocking libraries so I've resorted to passing in functions (which I can then test via mocking) then writing wrappers to simplify the signature, like so:
(defn f [g x y z]
...
(g x y z)
...)
(defn g [x y z]
(g x y z))
(defn f2 [x y z]
(f g x y z))
That seems like a bit of a contrived example, but it enables me to test f
and g
independently of each other, but it definitely feels a bit clunky. What do people do in the real world?
@djtango: You don’t want to mock functions that have no side-effects.
If a function has side effects, I tend to wrap the I/O resource it uses in a protocol, which I can then mock out in tests.
@weavejester: thanks for getting back to me! Interesting about mocking the protocols- will look into that. As for non-side effect functions, how do you test very large functions?
Ideally you shouldn’t have very large functions 🙂
I/O connections are often wrapped in a library like Component, which can be mocked with Shrubbery.
Precisely, so you have lots of small functions and functions that call the smaller functions?
Right. I think that tests can reveal complexity in your code. In Ruby, a system that’s difficult to mock usually indicates a problem. In Clojure, a system that’s difficult to test functionality often has a similar issue.
It’s only a rough rule of thumb, but quite useful.
But when testing the functions that call functions, what do you test? If you test the output, are you replicating the tests of the smaller functions?
@djtango maybe you dont need many tests for the smaller fns
@danlebrero: interesting - so approach your code with desired behaviour and transformation for your data in mind and test on that? Use extraction of functions as a tool primarily for readability?
I try to avoid testing side effects
I never liked mocking
see http://blog.josephwilk.net/clojure/isolating-external-dependencies-in-clojure.html
Yes, I tend to test only the public functions. Splitting functions into smaller parts aids readability and also tends to reduce complexity.