This is a library for stubbing out HTTP requests in Clojure. It supports both clj-http and http-kit clients with a consistent API.
(ns myapp.test.core
(:require [clj-http.client :as c])
(:use clj-http.clj_stub))
(ns myapp.test.core
(:require [org.httpkit.client :as http])
(:use httpkit.kit_stub))
The public interface consists of macros:
with-http-stub
- lets you override HTTP requests that match keys in the provided mapwith-http-stub-in-isolation
- does the same but throws if a request does not match any keywith-global-http-stub
with-global-http-stub-in-isolation
'Global' counterparts use with-redefs
instead of binding
internally so they can be used in
a multi-threaded environment (only available for clj-http).
The API is identical for both clj-http and http-kit, with the only difference being that http-kit uses callbacks/promises while clj-http is synchronous:
;; With clj-http:
(with-http-stub
{"http://api.example.com/data"
(fn [request] {:status 200 :headers {} :body "Hello World"})}
(c/get "http://api.example.com/data"))
;; With http-kit:
(with-http-stub
{"http://api.example.com/data"
(fn [request] {:status 200 :headers {} :body "Hello World"})}
@(http/get "http://api.example.com/data"))
;; Route matching examples (works the same for both clients):
(with-http-stub
{;; Exact string match:
"http://google.com/apps"
(fn [request] {:status 200 :headers {} :body "Hey, do I look like Google.com?"})
;; Exact string match with query params:
"http://google.com/?query=param"
(fn [request] {:status 200 :headers {} :body "Nah, that can't be Google!"})
;; Regexp match:
#"https://([a-z]+).packett.cool"
(fn [req] {:status 200 :headers {} :body "Hello world"})
;; Match based on HTTP method:
"http://shmoogle.com/"
{:get (fn [req] {:status 200 :headers {} :body "What is Scmoogle anyways?"})}
;; Match multiple HTTP methods:
"http://doogle.com/"
{:get (fn [req] {:status 200 :headers {} :body "Nah, that can't be Google!"})
:delete (fn [req] {:status 401 :headers {} :body "Do you think you can delete me?!"})
:any (fn [req] {:status 200 :headers {} :body "Matches any method"})}
;; Match using query params as a map
{:address "http://google.com/search" :query-params {:q "aardark"}}
(fn [req] {:status 200 :headers {} :body "Searches have results"})
;; If not given, the stub response status will be 200 and the body will be "".
"https://duckduckgo.com/?q=ponies"
(constantly {})}
;; Your tests with requests here
)
You can specify and validate the number of times a route should be called using the :times
option. There are two supported formats:
The :times
option can be specified as a sibling of the HTTP methods:
;; With clj-http:
(with-http-stub
{"http://api.example.com/data"
{:get (fn [_] {:status 200 :body "ok"})
:times 2}}
;; This will pass - route is called exactly twice as expected
(c/get "http://api.example.com/data")
(c/get "http://api.example.com/data"))
;; With http-kit:
(with-http-stub
{"http://api.example.com/data"
{:get (fn [_] {:status 200 :body "ok"})
:times 2}}
;; This will pass - route is called exactly twice as expected
@(http/get "http://api.example.com/data")
@(http/get "http://api.example.com/data"))
;; Multiple methods with shared count
(with-http-stub
{"http://api.example.com/data"
{:get (fn [_] {:status 200 :body "ok"})
:post (fn [_] {:status 201 :body "created"})
:times 1}}
(c/get "http://api.example.com/data")
(c/post "http://api.example.com/data"))
For more granular control, :times
can be a map specifying counts per HTTP method:
(with-http-stub
{"http://api.example.com/data"
{:get (fn [_] {:status 200 :body "ok"})
:post (fn [_] {:status 201 :body "created"})
:times {:get 2 :post 1}}}
;; This will pass - GET called twice, POST called once
(c/get "http://api.example.com/data")
(c/get "http://api.example.com/data")
(c/post "http://api.example.com/data"))
The :times
option allows you to:
If the actual number of calls doesn't match the expected count, an exception is thrown with a descriptive message.
If :times
is not supplied, the route can be called any number of times.
The library provides the following URL matching capabilities:
Default ports:
;; These are equivalent:
"http://example.com:80/api"
"http://example.com/api"
Trailing slashes:
;; These are equivalent:
"http://example.com/api/"
"http://example.com/api"
Default schemes:
;; These are equivalent:
"http://example.com"
"example.com"
Query parameter order independence:
;; These are equivalent:
"http://example.com/api?a=1&b=2"
"http://example.com/api?b=2&a=1"
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close