PSPDFKit-labs/bypass

Cannot wait (with timeout) for expectations

开放

#112 创建于 2020年10月26日

 (4 条评论) (4 个反应) (0 位负责人)Elixir (89 个派生)batch import
help wanted

仓库指标

星标
 (847 个星标)
PR 合并指标
 (30 天内没有已合并 PR)

描述

# inspired from https://hexdocs.pm/phoenix/testing.html
test "GET /", %{conn: conn} do
  bypass = Bypass.open(port: 4204)

  conn = get(conn, "/welcome")
  
  assert html_response(conn, 200) =~ "Welcome to Phoenix!"
  Bypass.expect_once(bypass, "POST", "/an/external/service", fn conn ->
    Plug.Conn.resp(conn, 201, "")
  end)
end

This is a nice and clean phoenix integration test. It verifies that, when a GET request hits the /welcome route:

  • a 200 response is returned
  • an html response is returned with the "Welcome to Phoenix!" body
  • an external service is contacted once with a POST on the /an/external/service route

Everything is good, until we face a different (quite common) async scenario.

Let's imagine that our Phoenix application, when it receives the /welcome GET request, it spawns a new process to contact the external service and it response synchronously with the 200 response. Since with ExUnit the verify_expectations is executed with hooks automatically at the end of the test:

  • if the the test ends after the external service invocation in the async process, the test goes well
  • if the the test ends before the external service invocation in the async process, the expectation fails

Usually popular http mocking frameworks solve this problem adding some waiting capabilities to the expectations (ie. do not fail immediately, do it if expectations are not satisfied in xxxx seconds). We could add some options as keyword list as last optional argument:

Bypass.expect_once(bypass, "POST", "/an/external/service", fn conn ->
  Plug.Conn.resp(conn, 201, "")
end, timeout: 2_000, polling_interval: 400)

What do you think? I would be happy to work on it and I have some ideas:

  • check polling bypass instance process (with the provided polling_interval) if the expectations are satisfied
  • use message passing and take advantage of receive with timeout otp functionalities
  • do not change expectation functions, but provide a separated function to sleep (with timeout) at the end of the test that bypass received some requests (eg. Bypass.wait_to_receive(bypass_instance, request_count: 3, timeout: 2_000))

贡献者指南