Last active
January 13, 2018 11:54
-
-
Save naiquevin/e37002b7c88e153d4a9c4afe08ffaf81 to your computer and use it in GitHub Desktop.
Generative mocking using circleci/bond and core.spec (IN/Clojure 2018 lightning talk)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns inclojure-mocks) | |
;; IN/Clojure 2018 lightning talk :: 13/01/2018 | |
;; | |
;; Topic: Mocking code (mainly for writing tests) | |
;; | |
;; Will be covered: | |
;; | |
;; 1. Mocking code using circleci/bond library | |
;; 2. Generating mocks for code using core.spec and test.check | |
;; | |
;; Will *NOT* be covered: | |
;; | |
;; 1. What is mocking, why mocking etc. | |
;; 2. core.spec and test.check | |
(defn fetch-data | |
"A fn that fetches data over network" | |
[x y] | |
{:conf "IN/Clojure" | |
:year 2018 | |
:location "Bangalore, India"}) | |
(defn foobar | |
"Fetches data over network and processes it" | |
[] | |
(let [{:keys [year conf location]} (fetch-data 1 2)] | |
(when year | |
(if (even? year) | |
conf | |
location)))) | |
(comment | |
(foobar)) | |
;; mocking using bond | |
(comment | |
;; https://github.com/circleci/bond | |
(require '[bond.james :as bond]) | |
(bond/with-spy [fetch-data] | |
(let [result (foobar) | |
calls (bond/calls fetch-data)] | |
(print "Result:") | |
(prn result) | |
(print "fetch-data calls:") | |
(prn calls) | |
[result calls])) | |
(def calls (second *1)) | |
(count calls) | |
(:args(first calls)) | |
(:return (first calls)) | |
(bond/with-stub [fetch-data] | |
(let [result (foobar)] | |
(print "Result:") | |
(prn result) | |
(print "fetch-data calls:") | |
(prn (bond/calls fetch-data)))) | |
(bond/with-stub [[fetch-data (constantly {:conf "Clojure Conj" | |
:year 2017 | |
:location "USA"})]] | |
(let [result (foobar)] | |
(print "Result:") | |
(prn result) | |
(print "fetch-data calls:") | |
(prn (bond/calls fetch-data))))) | |
;; With core.spec and test.check | |
(comment | |
;; https://github.com/clojure/core.specs.alpha | |
;; https://github.com/clojure/test.check | |
(require '[clojure.spec :as s]) | |
(require '[clojure.spec.gen :as gen]) | |
(s/def ::conf (s/and string? #(re-matches #"^\w+$" %))) | |
(s/def ::location (s/and string? #(re-matches #"^\w+$" %))) | |
;; generators for free | |
(gen/generate (s/gen ::conf)) | |
(gen/generate (s/gen ::location)) | |
;; or your can define a spec with a custom generator | |
(s/def ::year (s/with-gen number? | |
#(gen/choose 2010 2018))) | |
;; composing individual specs into a larger spec | |
(s/def ::resp-data (s/keys :req-un [::conf ::year ::location])) | |
(gen/generate (s/gen ::resp-data)) | |
(defn mocker-for-resp-data | |
[] | |
(fn [& _] | |
(let [mock-data (gen/generate (s/gen ::resp-data))] | |
(println "Mock data") | |
(prn mock-data) | |
mock-data))) | |
(bond/with-stub [[fetch-data (mocker-for-resp-data)]] | |
(let [result (foobar)] | |
(print "Result:") | |
(prn result) | |
(print "fetch-data calls:") | |
(prn (bond/calls fetch-data))))) | |
;; Now we can integrate the above example with core.test, asserting on | |
;; result and/or bond/calls data | |
;; Summary: | |
;; | |
;; mocking provided by bond + data generation using core.spec = super | |
;; fast and maintainable tests! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment