Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Testing Asynchronous OTP
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Andrea Leopardi
September 09, 2021
Programming
580
1
Share
Testing Asynchronous OTP
Andrea Leopardi
September 09, 2021
More Decks by Andrea Leopardi
See All by Andrea Leopardi
Agentic Elixir
whatyouhide
0
470
The Umbrella and the Range
whatyouhide
0
64
gen_statem - OTP's Unsung Hero
whatyouhide
2
340
The World is a Network (and We Are Just Nodes)
whatyouhide
1
260
BEAM: The Perfect Fit for Networks
whatyouhide
1
260
Update from the Elixir team - 2022
whatyouhide
0
460
Elixir Sightseeing Tour
whatyouhide
0
480
Mint - Disrupting HTTP clients
whatyouhide
0
300
BEAM Architecture Handbook
whatyouhide
7
3k
Other Decks in Programming
See All in Programming
tsserverとは何だったのか、これからどうなるのか
nowaki28
1
440
柔軟なPDFレイアウトエディタを支える型システム設計 — Discriminated UnionとConditional Typeの実践
minako__ph
4
1.3k
3Dシーンの圧縮
fadis
1
590
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
120
さぁV100、メモリをお食べ・・・
nilpe
0
130
Lessons from Spec-Driven Development
simas
PRO
0
130
GitHub Copilot CLIのいいところ
htkym
2
1.2k
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
220
プロパティの順序で型推論が壊れる!? TypeScript6.0の修正からContext-Sensitivityの仕組みを追う
bicstone
2
1.3k
New "Type" system on PicoRuby
pocke
1
430
Claspは野良GASの夢をみるか
takter00
0
160
RTSPクライアントを自作してみた話
simotin13
0
440
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
55
8.2k
A better future with KSS
kneath
240
18k
Principles of Awesome APIs and How to Build Them.
keavy
128
17k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
240
The SEO identity crisis: Don't let AI make you average
varn
0
480
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
830
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.8k
Building AI with AI
inesmontani
PRO
1
1k
How to Think Like a Performance Engineer
csswizardry
28
2.6k
Paper Plane
katiecoart
PRO
1
51k
Code Reviewing Like a Champion
maltzj
528
40k
Transcript
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
defmodule RollingAverage do use GenServer def start_link(limit), do: # ...
def add(pid, n), do: # ... def average(pid), do: # ... end
None
None
test "add/2" do {:ok, pid} = RollingAverage.start_link() RollingAverage.add(pid, 3) #
Now what? end
None
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
None
defmodule RollingList do def new(limit), do: {limit, []} def add({limit,
list}, n), do: # ... def average({_limit, list}), do: # ... end
test "add/2" do rolling_list = RollingList.new(2) assert RollingList.add(rolling_list, 3) ==
{_limit = 2, [3]} end
None
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
None
None
test "add/2 and average/1" do {:ok, pid} = start_supervised( {RollingAverage,
_limit = 2} ) # Same as before end
None
def background_work do Task.start(fn -> do_something() end) end
None
None
def background_work(parent, ref) do Task.start(fn -> do_something() send(parent, {ref, :done})
end) end
test "background_work/0" do ref = make_ref() background_work(self(), ref) assert_receive {^ref,
:done} end
None
def background_work do Task.start(fn -> :ok = twitter_module.post() end) end
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
None
defmodule WeatherChecker do use GenServer def init(_) do :timer.send_interval(5000, self(),
:tick) end def handle_info(:tick, _) do check_weather() end end
test "checking weather periodically" do {:ok, _pid} = WeatherChecker.start_link() Process.sleep(5000
* 1.5) assert weather_checked?() end
None
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
test "checking weather periodically" do {:ok, pid} = WeatherChecker.start_link() WeatherChecker.tick(pid)
assert weather_checked?() end
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
None
@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 | ...]
None
None
None
None
test "cleanup after crashes" do Process.flag(:trap_exit, true) {:ok, pid} =
start_supervised(MyServer) Process.exit(pid, :kill) assert cleanup_successful?() end
None
None
None
None
None
None
None
None
None
None