HackerRank Code Testing by Clojure
HackerRank Code Testing by Clojure
Recently, I decided to give Clojure a try. I used to write Clojure code for my day job, however, no Clojure at all for two years. Instead, almost all were done by Python. I became familiar with Python’s functional programming world now. Aside of ML/DL projects, I did bunch at HackerRank, leetcode or sort. After a while, I thought, “maybe I can solve problems by Clojure like Python…”
Luckily, HackerRank supports Clojure. So, I started.
Soon, I hit the wall. I wanted to test a code. Okay, writing test is not hard.
Something quite hard was the HackerRank platform.
Test data comes in from
STDIN. Something output to
STDOUT is tested.
For many problems, it’s effective to have
println in the code side.
I did quite a lot of research and trials so that the code can be tested without any modification on HackerRank platform. This experience, setting up a testing environment was a good Clojure study. That’s why I wrote the blog post. This post may help other Clojure newbies to figure out how.
This function is used to create new bindings, which is like, replacing the current bindings.
STDIN is bind to
So, what should be done is to bind
*in* to something else.
Next question is what should be “something else.”
HackerRank test case is provided by a file.
People can get the test data file if they pay 5 Hackos.
The “Hackos” are points people can get when their solutions successfully pass all tests.
Unless the problem is a very entry level, the test case file tends to pretty big.
It’s unable to write the test data in the code often.
For this reason, I wanted to get the test data from a file and bind it to
What I did was:
- create a file under
- read it as a resource
- convert it to a reader
- bind the reader to
(require '[clojure.java.io :as io]) (with-open [rdr (io/reader (io/resource n))] (binding [*in* rdr] (f)))
Since the project was created by the
resources directory is already on the path. Just to give a relative file path
n, the file is read. The
f is a function which consumes data from
Now, reading from
STDIN was cleared. Next will be to catch
Clojure has a convenient function
Compared to a reading part, catching
STDOU was much easier.
;; define function which prints to stdout > (defn say-it  (println "seriously?") (println "can't believe")) ;; assign STDOUT to "out" > (def out (with-out-str (say-it))) ;; what's in the "out" > out "seriously?\ncan't believe\n"
The same idea for the reading can be applied to
STDOUT – printing out to a file under
However, in general, the expected output is simple for the HackerRank problems.
At this moment,
with-out-str function satisfies my needs.
STDOUT work well to fit with the HackerRank platform.
However, to bind resource reader to
STDIN, I should write
with-open ... in every test case.
I want to avoid writing the same lines again and again.
After searching online, I found
This function works like Unit test’s
As the Clojure API document explains:
(defn my-test-fixture [f] (create-db) ;; setUp (f) ;; test (destroy-db)) ;; tearDown (use-fixtures :once my-test-fixture
Define the fixture function, then call
The tests in the same namespace are all wrapped by the fixture.
Below is an example test by the
use-fixture made my test code simple. It’s good.
However, it has a downside.
Some problems provide multiple test cases, which means multiple resource files on my test environment.
Since only one
use-fixture is applied to all tests in the same namespace,
wrap-test and fixture design don’t work nicely.
There should be a way to cope with this problem.
It will be my next challenge.