Fork me on GitHub
Noah Bogart17:08:07

is there any good method for mocking something like java.util.Date. ? I am creating a map with a :date entry and don’t want to have to worry about what it actually is when testing against the other contents

Noah Bogart17:08:30

i know i could write (map #(dissoc % :date)) in my test but that’s so cumbersome, especially when writing multiple tests

Noah Bogart17:08:35

i’d prefer to just write (= [{:date nil :text "Hello!"}] (-> (sut/new-game) (sut/add-message "Hello!") (:messages)))

Noah Bogart17:08:06

i just had the thought that a simple (defn new-date [] (java.util.Date.)) allows me to use with-redefs , but is that doesn’t seem generalizable. It will work for now so I’m not going to spend more time on this, but i’m still curious


Date. is akin to a side-effect. Some call it a side-cause or "coeffect"

👍 2
Russell Mull17:08:28

if your code depends on the clock, then you should consider giving it a now parameter


^ exactly, that way you seggregate the side-cause

Russell Mull17:08:02

lol, side-cause is a great name

Noah Bogart17:08:24

interesting. so how do i pass it in? i hope to allow the engine (for a game) to add messages from anywhere, which makes me think it’ll be cumbersome to have to call (java.util.Date.) every time I want to add a message

Noah Bogart17:08:42

once I’ve done it a couple times i start thinking “okay, how do I refactor to remove duplication?”

Russell Mull17:08:00

you could have a little message constructor that captures the clock

Russell Mull17:08:29

(defn messasge [m] {:msg m :time (java.util.Date)})

Russell Mull17:08:07

wow, I'm completely incapable of typing today

Noah Bogart17:08:28

so I would call (add-message game (message "Hello!")) in the engine instead of (add-message game "Hello!")? and in a test I can just pass in (sut/add-message game {:date nil :text "Hello!"})?

Russell Mull17:08:58

sure, that's reasonable

Noah Bogart17:08:32

seems like all i’ve done is move the (java.util.Date.) from within add-message to message. maybe I don’t understand enough, or maybe I haven’t done a good enough job of showing my code up front lol

Noah Bogart17:08:37

classic X/Y problem

Noah Bogart17:08:44

(defn add-message [game message]
  (update game :messages conj {:date (java.util.Date.)
                               :text message}))

Russell Mull17:08:57

what are you trying to do by putting a nil in for the date?

Noah Bogart17:08:29

allow me to test against the whole :messages vector without having to deliberately exclude the :date key in my equality checks

👍 2

Hey @UEENNMX0T - sorry for resurrecting a week-old thread, but I think this is some real insight that may have been overlooked. > allow me to test against the whole `:messages` vector without having to deliberately exclude the `:date` key in my equality checks Irrespective of whether you want to have an external clock passed to functions (so you can test and easily control behavior based on time); if what you want to do is check equality without dates; then that is code that should exist somewhere directly in the test codebase:

(is (= expected-msgs (elide-dates generated-msgs)))
How you implement eldie-dates is up to you; it could be as simple as a helper function that does dissoc on each message in the collection, or it could use some fancy testing matching library (ala or some fancy data wrangling library (ala or or some fancy query library (ala

Noah Bogart19:08:49

ha I wrote get-messages which does what your elide-dates does: (defn get-messages [game] (mapv #(dissoc % :date) (:messages game))) . Glad to know i’m not too far off

Jacob Emcken15:03:53

This is an alternative which actually mocks "creating a date", whether it is better or worse 🤷

Jacob Emcken15:03:49

(defn now []
(def freezed-time #inst "2022-03-09T15:54:02.699-00:00")
(with-redefs [now (constantly freezed-time)]
  (= (now) #inst "2022-03-09T15:54:02.699-00:00")) => true

👍 1
Noah Bogart15:03:41

That’s a good one too!

Jacob Emcken16:03:47

If you ever start using the "newer" (immutable) dates in Java: They have a built-in with-clock that can help you mock time in tests:

(with-clock (system-clock "UTC")
  (zoned-date-time 2015 10))
=> #<java.time.ZonedDateTime 2015-10-01T00:00Z[UTC]>

Russell Mull17:08:56

ahh, I see. In that case, moving it does have some value.

👍 2
Russell Mull17:08:32

Another possibility, which I kind of hesitate to mention: if two messages are logically equal even if the dates are different, then perhaps the date should be metadata.

Russell Mull17:08:10

but it sounds like that's not the case, instead it's just for the test assertion.


defn add-message [game message {:keys [date] :or {:date (Date.)}}]
poor man's DI / Functional Architecture

Noah Bogart18:08:55

oh! that’s clever