danschultzer
TestServer - No fuzz mocking of third-party services
Hi everyone!
TestServer is an easy way to mock third-party services in ExUnit.
Features
- HTTP/1
- HTTP/2
- WebSocket
- TLS with self-signed certificates
- Flexible FIFO match rules
- Catches unexpected requests
- When test finishes verifies there’s no pending routes or websocket handlers to call
Example
test "fetch_url/0" do
# The test server will autostart the current test server, if not already running
TestServer.add("/", via: :get)
TestServer.add("/", via: :get, to: fn conn -> Plug.Conn.send_resp(conn, 200, "second call") end)
# The URL is derived from the current test server instance
Application.put_env(:my_app, :url, TestServer.url())
assert {:ok, "HTTP"} = MyApp.fetch_url()
assert {:ok, "second call"} = MyApp.fetch_url()
end
Enabling TLS
TestServer.start(scheme: :https)
The key and certificate is generated with x509 on the fly.
WebSocket Example
test "WebSocketClient" do
{:ok, socket} = TestServer.websocket_init("/ws")
:ok = TestServer.websocket_handle(socket, to: fn {:text, "ping"}, state -> {:reply, {:text, "pong"}, state})
{:ok, client} = WebSocketClient.start_link(TestServer.url("/ws"))
:ok = WebSocketClient.send(client, "ping")
{:ok, "pong"} = WebSocketClient.receive(client)
:ok = TestServer.websocket_info(socket, fn state -> {:reply, {:text, "ping"}, state} end)
{:ok, "ping"} = WebSocketClient.receive(client)
end
I’ve been using this for testing a JSON RPC endpoint and testing the SSL configuration for http adapters in assent.
I hope you find it useful, feel free to contribute! ![]()
Most Liked
danschultzer
New exiciting release!
v0.1.8 no longer has Plug.Cowboy as a required dependency, and instead will use Bandit, Plug.Cowboy, or :httpd depending what is available (in that order). You can also set up a custom web server.
My own belief is that libraries should attempt limit the dependency graph as much as possible. This helps prevent dreaded dependency conflicts, improve auditing, and maybe even helps with perfomance/build time gains.
And I didn’t know :httpd was a thing! Included in OTP so of course TestServer should support it as the default web server if Bandit or Plug.Cowboy is not available. I’ve seen almost no love for :httpd, and maybe that’s for a reason.
All to say, now there’s only two required dependency left in TestServer - the x509 package and Plug.
Try it out and let me know what you think!
danschultzer
Especially being able to define multiple rules for the same url, which is something you can’t do in Bypass and has always annoyed me.
True, it was what prompted me to build this library. JSON RPC was impossible to test well with bypass. On top of that I couldn’t use bypass to test handling of bad SSL certificates, and I wished it was a lot more ergonomic for request matching.
trisolaran
Hi @danschultzer thanks for releasing this. This looks like a considerable improvement over Bypass. Especially being able to define multiple rules for the same url, which is something you can’t do in Bypass and has always annoyed me. Will try this out as soon as I have to write the next test for an external service.
danschultzer
This release makes it a lot easier to test IPv6-only networks. All you need to do is set the :ipfamily option:
TestServer.start(ipfamily: :inet6)
rhcarvalho
I’ve been trying to replace Bypass + Mox with TestServer, and I really appreciate the simplification and ease of understanding it brought back to my tests ![]()
The one case that’s been bugging me and preventing me from shipping it is how to handle a test involving Phoenix.Presence. As far as I understand, depending on timing/scheduling my test server gets hit with a different number of requests.
If I TestServer.add one too little I get a warning in the test output, even though the test passes:
warning: ** (RuntimeError) TestServer.Instance #PID<0.471.0> received an unexpected GET request at /v1/users/79e78660-718c-4f59-8e4c-51b61599d868
If I TestServer.add one too many, then the test fails:
(RuntimeError) TestServer.Instance #PID<0.465.0> did not receive a request for these routes before the test ended
Is there a blessed way in TestServer to say “this handler should match at least once (or N times)?”
Alternatively, any other ideas of what I could consider doing? Thanks!







