danschultzer

danschultzer

Pow Core Team

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! :love_you_gesture:

Most Liked

danschultzer

danschultzer

Pow Core Team

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!

https://hexdocs.pm/test_server/

danschultzer

danschultzer

Pow Core Team

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

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

danschultzer

Pow Core Team

v0.1.9 is out!

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

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 :purple_heart:

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!

Where Next?

Popular in Libraries Top

woutdp
Hi! I wanted to introduce my latest project LiveSvelte. It allows you to render Svelte inside LiveView with end-to-end reactivity. It’s ...
New
benlime
LiveMotion enables high performance animations declared on the server and run on the client. As a follow up to my previous thread A libr...
New
Qqwy
Hello everyone, I wrote a small library today called MapDiff. It returns a map listing the (smallest amount of) changes to get from map...
New
zorbash
I created Kitto a framework for dashboards inspired by Dashing. [demo] The distributed characteristics of Elixir and the low memory foo...
New
ahamez
Hi everyone, I’ve been working on this protobuf library for 3 years. We use it in the company I work for, EasyMile, to communicate with ...
New
wmnnd
Hi there, for my project DBLSQD, I needed a file storage solution that is a bit more flexible than Arc. Because I thought others might f...
New
engineeringdept
I’ve just released the first version of Snap, an Elasticsearch client. It borrows ideas about application structure and process managemen...
New
bryanjos
Hi, I wanted share a small library we at Revelry Labs made for rendering react components from the server side. There are instructions fo...
New
mischov
import Meeseeks.CSS html = HTTPoison.get!("https://news.ycombinator.com/").body for story &lt;- Meeseeks.all(html, css("tr.athing")) do...
New
wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New

Other popular topics Top

chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New

Sub Categories:

We're in Beta

About us Mission Statement