When testing HTTP calls made by your Mix application, your options are to either fire them to the real HTTP endpoint (requires net availability and may count against an API's rate limit) or use a mock (be it is a noun or a verb).
Or you could fire real HTTP requests to a real in promptu webserver instead. Rodeo spawns one-off cowboy webserver instances that reply based on a simple handler API.
(Cowboy… Rodeo… get it?)
- Add
rodeo
to your list of dependencies inmix.exs
:
def deps do
[{:rodeo, "~> 0.3.0"}]
end
- Ensure
rodeo
is started before your application. Also, you need to addcowboy
:
def application do
[applications: [:cowboy, :rodeo]]
end
Rodeo provides with_webserver
that can be used in a test case:
defmodule MyApp.APIClientTest do
use ExUnit.Case
use Rodeo.HTTPCase
test "will start a new cowboy server on a free tcp port" do
with_webserver fn rodeo ->
# rodeo is a %Rodeo{} struct, holding the port of the web server
assert HTTPoison.get!("http://127.0.0.1:#{rodeo.port}/") == "Hello World"
end
# The webserver is torn down again at this point
end
test "uses a custom request handler" do
defmodule Teapot do
use Rodeo.Handler
def body(_req), do: "I'm a teapot"
def status(_req), do: 418
end
with_webserver Teapot, fn rodeo ->
# Rodeo.base_url is a convenience function to
# glue scheme, ip and port together
assert HTTPoison.get!(Rodeo.base_url(rodeo) <> "/earl-grey") == "I'm a teapot"
end
end
end
Rodeo provides Rodeo.Handler
that can be used as a template for custom handlers (see module documentation).
defmodule MyApp.InternalServerError do
use Rodeo.Handler
def status(_), do: 500
def body(_), do: "Oooops!"
def headers(_), do: [{"X-Reason", "Server rolled a 1"}]
end