Thursday, July 28, 2016

Revisited Kata: Using Midje's defrecord-openly to mock a protocol in Ohce

Several weeks ago I did the Ohce kata in Clojure using outside-in TDD with Midje (as I explained in a previous post).

In that post I said that I hadn't used Midje's defrecord-openly and provided macros and had instead decided to write my own code to capture the arguments with which the functions of the Notifier protocol implementation were being called because:
... I didn't like having to use defrecord-openly in production code.
Well, I was wrong!

It turns out that it is not necessary at all to use defrecord-openly in your production code in order to mock a protocol.

I understood it thanks to this answer in Stak Overflow: Mocking Clojure protocols.

The only thing I needed to do was to use defrecord-openly to create a fake implementation of the Notifier protocol inside the test code like this:

(unfinished greet)
(unfinished echo)
(unfinished palindromes-rock)
(unfinished bye-user)
(defrecord-openly FakeNotifier []
notifications/Notifier
(greet [this greeting])
(echo [this reversed-phrase])
(palindromes-rock [this])
(bye-user [this name]))
and then write the tests against this unimplemented fake.

This are the new Ohce tests:

(ns ohce.unit-tests.ohce-test
(:require
[midje.sweet :refer :all]
[ohce.ohce :refer :all]
[ohce.notifications :as notifications]
[midje.open-protocols :refer [defrecord-openly]]))
(unfinished select-greeting)
(unfinished read-input)
(unfinished greet)
(unfinished echo)
(unfinished palindromes-rock)
(unfinished bye-user)
(defrecord-openly FakeNotifier []
notifications/Notifier
(greet [this greeting])
(echo [this reversed-phrase])
(palindromes-rock [this])
(bye-user [this name]))
(facts
"about ohce"
(fact
"it greets the user"
(let [notifier (->FakeNotifier)
stop-word "Stop!"]
(ohce select-greeting notifier read-input stop-word ...username...) => irrelevant
(provided
(read-input) => "Stop!"
(select-greeting ...username...) => ...greeting...
(greet notifier ...greeting...) => irrelevant :times 1)))
(fact
"it reverses the user inputs"
(let [notifier (->FakeNotifier)
stop-word "Stop!"]
(ohce select-greeting notifier read-input stop-word ...username...) => irrelevant
(provided
(select-greeting ...username...) => irrelevant
(read-input) =streams=> ["hola" "lolo" "Stop!"]
(echo notifier "aloh") => irrelevant :times 1
(echo notifier "olol") => irrelevant :times 1)))
(fact
"it ignores inputs that are blank"
(let [notifier (->FakeNotifier)
stop-word "Stop!"]
(ohce select-greeting notifier read-input stop-word ...username...) => irrelevant
(provided
(select-greeting ...username...) => irrelevant
(read-input) =streams=> ["memo" "" "moko" "Stop!"]
(echo notifier "omem") => irrelevant :times 1
(echo notifier "okom") => irrelevant :times 1)))
(fact
"it identifies palindromes"
(let [notifier (->FakeNotifier)
stop-word "Stop!"]
(ohce select-greeting notifier read-input stop-word ...username...) => irrelevant
(provided
(select-greeting ...username...) => irrelevant
(read-input) =streams=> ["oto" "ana" "Stop!"]
(echo notifier "oto") => irrelevant :times 1
(echo notifier "ana") => irrelevant :times 1
(palindromes-rock notifier) => irrelevant :times 2)))
(fact
"it knows when to stop"
(let [notifier (->FakeNotifier)
stop-word "Stop!"]
(ohce select-greeting notifier read-input stop-word ...username...) => irrelevant
(provided
(select-greeting ...username...) => irrelevant
(read-input) =streams=> ["Stop!"]
(bye-user notifier ...username...) => irrelevant :times 1))))
As you can see it's very easy to use Midje's defrecord-openly to mock protocols.

I just misunderstood Midje's documentation the first time I tried to do it...

No comments:

Post a Comment