I’ve got a Genserver that writes messages to stdout. I can’t figure out how to test using capture_io
. Documentation says By default, capture_io replaces the group_leader (:stdio) for the current process
. Perhaps there is a Process.group_leader
call that will make this work, but I haven’t been able to find it. Can anyone point me to a solution?
Here’s a failing test script…
#!/usr/bin/env elixir
ExUnit.start()
defmodule MyGenServer do
use GenServer
def start_link(default \\ []) do
GenServer.start_link(__MODULE__, default, name: __MODULE__)
end
def init(initial_state) do
{:ok, initial_state}
end
def handle_call(:sayhi, _caller, state) do
IO.puts("HI")
{:reply, :ok, state}
end
end
defmodule MyGenServerTest do
use ExUnit.Case
import ExUnit.CaptureIO
test "GenServer responds to :sayhi call by writing 'HI' to stdout" do
{:ok, pid} = MyGenServer.start_link()
assert capture_io(fn -> GenServer.call(pid, :sayhi) end) == "HI\n"
end
end
1 Like
I could make it work with capture_log
+ import ExUnit.CaptureLog
+ require Logger
inside both modules + actually using Logger.debug
(or any other level) and not IO.puts
but curiously enough I wasn’t able to make it work with capture_io
like in your original script. Also tried with with_io
but no dice again. Interesting.
2 Likes
Ya, this was the closest I could find to an answer which is probably something you’ve already come across at this point. I may be brain-farting due to fatigue but I couldn’t quite get it to work with GenServer. I did run into this a while back so I’m pretty curious. It’s not in code I have access to anymore but I think I ended up just going with the repeated advice I keep coming across which is to test behaviour by asserting on the callbacks directly then I guess you can just assert_receive
to test the API layer? I honestly don’t quite remember what I did. Sorry if this isn’t very helpful.
2 Likes
The problem is that you have to set the group leader first, which doesn’t seem possible with the way that capture_io/1
currently works:
# group leader is set before starting the GenServer, so this works
assert ExUnit.CaptureIO.capture_io(fn ->
{:ok, pid} = MyGenServer.start_link()
GenServer.call(pid, :sayhi)
GenServer.stop(pid)
end) == "HI\n"
I wonder what the ideal way to do this would be. If we had some way of telling capture_io
to use the pid of the GenServer, then it could properly set the group leader.
Maybe something like this:
{:ok, pid} = MyGenServer.start_link()
assert ExUnit.CaptureIO.capture_io([pid: pid], fn -> GenServer.call(pid, :sayhi) end)
1 Like
@voughtdq grateful for your solution – thank you! I thought I had tried all permutations, but not that one!