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

Qqwy
While not as prevalent as in imperative languages, arrays (collections with efficient random element access) are still very useful in Eli...
New
josevalim
Hi everyone, We would like to announce that Plataformatec is working on a new MySQL driver called MyXQL. Our goal is to eventually integ...
New
kip
Image is an image processing library for Elixir. It is based upon the fabulous vix library that provides a libvips wrapper for Elixir. I...
574 16576 179
New
deadtrickster
I’ve just released stable versions of my Prometheus Elixir libs: Elixir client [docs]; Ecto collector [docs]; Plugs instrumenter/Export...
New
riverrun
I’ve just released version 3 of Comeonin, a password hashing library. The following small changes have been made: changes to the NIF c...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
kelvinst
Hey everyone! Well, we made this lib a while ago and now we decided to finally go out and public with it! It’s a tool for creating and m...
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
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
Crowdhailer
Experimenting with this code. OK.try do user &lt;- fetch_user(1) cart &lt;- fetch_cart(1) order = checkout(cart, user) save_or...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
AstonJ
You’re a programmer, so you don’t need spoon feeding with the conventional drivel about “this is an integer.” No. You need to know what’s...
New
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

Sub Categories:

We're in Beta

About us Mission Statement