3

我想通过以下方法测试返回值和 IO 输出:

defmodule Speaker do
  def speak do
    receive do
      { :say, msg } ->
        IO.puts(msg)
        speak
      _other ->
        speak # throw away the message
    end
  end
end

ExUnit.CaptureIO文档中,有一个执行此操作的示例测试,如下所示:

test "checking the return value and the IO output" do
  fun = fn ->
    assert Enum.each(["some", "example"], &(IO.puts &1)) == :ok
  end
  assert capture_io(fun) == "some\nexample\n"
end

鉴于此,我认为我可以编写以下执行类似操作但使用spawned 进程的测试:

test ".speak with capture io" do
  pid = Kernel.spawn(Speaker, :speak, [])
  fun = fn ->
    assert send(pid, { :say, "Hello" }) == { :say, "Hello" }
  end
  assert capture_io(fun) == "Hello\n"
end

但是,我收到以下错误消息,告诉我没有输出,即使我可以在终端上看到输出:

1) test .speak with capture io (SpeakerTest)
   test/speaker_test.exs:25
   Assertion with == failed
   code: capture_io(fun) == "Hello\n"
   lhs:  ""
   rhs:  "Hello\n"
   stacktrace:
     test/speaker_test.exs:30: (test)

spawn那么,在测试ed 进程或使用receive宏的方法方面,我是否遗漏了一些东西?如何更改我的测试以使其通过?

4

2 回答 2

5

CaptureIO可能不适合您在这里尝试做的事情。它运行一个函数并在该函数返回时返回捕获的输出。但是你的函数永远不会返回,所以看起来这不起作用。我想出了以下解决方法:

test ".speak with capture io" do
  test_process = self()
  pid = spawn(fn ->
    Process.group_leader(self(), test_process)
    Speaker.speak
  end)

  send(pid, {:say, "Hello"})

  assert_receive {:io_request, _, _, {:put_chars, :unicode, "Hello\n"}}

  # Just to cleanup pid which dies upon not receiving a correct response
  # to the :io_request after a timeout
  Process.exit(pid, :kill)
end

它用于Process.group_leader将当前进程设置为被测进程的 IO 消息的接收者,然后断言这些消息到达。

于 2016-06-27T23:52:02.410 回答
0

我有一个类似的问题,我有一个注册进程,Application每 10 秒超时一次并写入 stdio IO.binwrite,以模拟我在@Pawel-Obrok 回答时采取的多次超时,但将其更改为用:io_request回复:io_reply该过程不会挂起,允许我发送多条消息。

defp assert_io() do
  send(MyProcess, :timeout)
  receive do
    {:io_request, _, reply_as, {:put_chars, _, msg}} ->
      assert msg == "Some IO message"
      send(Stats, {:io_reply, reply_as, :ok})

    _ ->
      flunk
  end
end

test "get multiple messages" do
  Process.group_leader(Process.whereis(MyProcess), self())
  assert_io()
  assert_io()
end

如果您想了解有关 IO 协议的更多信息,请查看有关它的 erlang 文档。

于 2018-05-06T16:54:32.033 回答