Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testing Asynchronous OTP

Testing Asynchronous OTP

Faafc04d9e69b73b9f49995fd4c94d4d?s=128

Andrea Leopardi

September 09, 2021
Tweet

Transcript

  1. None
  2. None
  3. None
  4. None
  5. None
  6. None
  7. None
  8. None
  9. None
  10. None
  11. None
  12. None
  13. None
  14. None
  15. None
  16. None
  17. None
  18. None
  19. None
  20. None
  21. None
  22. defmodule RollingAverage do use GenServer def start_link(limit), do: # ...

    def add(pid, n), do: # ... 
 def average(pid), do: # ... end
  23. None
  24. None
  25. test "add/2" do {:ok, pid} = RollingAverage.start_link() RollingAverage.add(pid, 3) #

    Now what? end
  26. None
  27. test "add/2 and average/1" do {:ok, pid} = RollingAverage.start_link(2) RollingAverage.add(pid,

    3) RollingAverage.add(pid, 4) assert RollingAverage.average(pid) == 3.5 RollingAverage.add(pid, 5) assert RollingAverage.average(pid) == 4.5 end
  28. None
  29. defmodule RollingList do def new(limit), do: {limit, []} def add({limit,

    list}, n), do: # ... def average({_limit, list}), do: # ... end
  30. test "add/2" do rolling_list = RollingList.new(2) assert RollingList.add(rolling_list, 3) ==

    {_limit = 2, [3]} end
  31. None
  32. test "add/2" do {:ok, pid} = RollingAverage.start_link(2) RollingAverage.add(pid, 3) state

    = :sys.get_state(pid) assert state == {_limit = 2, [3]} end
  33. None
  34. None
  35. test "add/2 and average/1" do {:ok, pid} = start_supervised( {RollingAverage,

    _limit = 2} ) # Same as before end
  36. None
  37. def background_work do Task.start(fn -> do_something() end) end

  38. None
  39. None
  40. def background_work(parent, ref) do Task.start(fn -> do_something() send(parent, {ref, :done})

    end) end
  41. test "background_work/0" do ref = make_ref() background_work(self(), ref) assert_receive {^ref,

    :done} end
  42. None
  43. def background_work do Task.start(fn -> :ok = twitter_module.post() end) end

  44. test "background_work/0" do parent = self() ref = make_ref() Mox.expect(TwitterMock,

    :post, fn -> send(parent, ref) :ok end) background_work() assert_receive ^ref end
  45. None
  46. defmodule WeatherChecker do use GenServer def init(_) do :timer.send_interval(5000, self(),

    :tick) end def handle_info(:tick, _) do check_weather() end end
  47. test "checking weather periodically" do {:ok, _pid} = WeatherChecker.start_link() Process.sleep(5000

    * 1.5) assert weather_checked?() end
  48. None
  49. defmodule WeatherChecker do use GenServer def init(_) do :timer.send_interval(5000, self(),

    :tick) end def tick(pid), do: send(pid, :tick) def handle_info(:tick, _) do check_weather() end end
  50. test "checking weather periodically" do {:ok, pid} = WeatherChecker.start_link() WeatherChecker.tick(pid)

    assert weather_checked?() end
  51. defmodule WeatherChecker do use GenServer def init(:interval) do :timer.send_interval(5000, self(),

    :tick) end def init(:manual) do # No send_interval end end
  52. None
  53. @mix_env Mix.env() def start(_type, _args) do Supervisor.start_link(children(@mix_env), ...) end defp

    children(:test), do: [...] defp children(_env), do: [WeatherChecker | ...]
  54. None
  55. None
  56. None
  57. None
  58. test "cleanup after crashes" do Process.flag(:trap_exit, true) {:ok, pid} =

    start_supervised(MyServer) Process.exit(pid, :kill) assert cleanup_successful?() end
  59. None
  60. None
  61. None
  62. None
  63. None
  64. None
  65. None
  66. None
  67. None
  68. None