Writing test that communicate with third party app

Writing test that communicate with 3rd party app isn't hard if you test each function one by one,
but if you need to test whole process and make sure something happen after something, something trigger by something, it might a little bit tricky.

Because you need to let test running like server, so you can receive response from 3rd party.

I solved this by doing something like :

  @tag timeout: set_a_longer_time_here
  setup do 
    :ets.new(your_ets_name, [:set, :public, :named_table, {:read_concurrency, true}])
  end
  test "" do 
    job blablabla
    job blablabla
    receive_loop()
  end
  def receive_loop() do 
    receive do 
      {:received, path, method, conn} -> receive_loop()
      {:after, path, method, conn} -> receive_loop()
    end
  end

As you can see, I start a endless loop during test, we can assert something during and continue loop, having some ifelse around to not continue loop when all assertion complete.

and create a Plug as :

defmodule RouterPlug do  
  defmacro __using__(_env) do
    quote do
      import Phoenix.Router
      import Riplog.Plug
      use Plug.ErrorHandler

      def call(conn, opts) do   
        path = conn.request_path
        method = conn.method
        pid = case :ets.lookup(your_ets_name, "pid") do 
          [{key,pid}]-> pid
          _-> nil
        end  
        if pid, do: send pid, {:received, path, method, conn}
        conn = do_call(conn, opts)
        if pid, do: send pid, {:after, path, method, conn}
        conn
      end 
    end  
  end 
end  

Plug into router.ex :

  defmodule MyApp.Router do 
    use RouterPlug
  end

This allow us to assert anything when we receive a request before and after code execution.

Testing one by one function only means that function should works, sometimes it goes wrong when we put them all together.

By this, we can get a whole picture.

That's all.