gpt4 book ai didi

erlang - EUnit 和 io :format

转载 作者:行者123 更新时间:2023-12-04 10:44:50 24 4
gpt4 key购买 nike

我想使用 EUnit 测试一些第三方 Erlang 代码。

代码函数的输出使用 io:format/2 显示到标准输出。 .我想捕获该输出并执行 ?assert测试将被打印出来的字符串。我无法修改第三方代码。

是用 Erlang 做到这一点的方法吗? (例如,在 Java 中,我可以简单地将 System.setOut() 用于输出流)。

更新:
group_leader/2似乎在正确的轨道上。

但是,我仍然不明白这是如何让我捕获 io:format 打印的字符串的。所以我可以测试我的断言。一个非常简化的代码示例是:

result(Value) ->
io:format("Result: ~w~n", [Value]).

test_result() ->
?assertMatch("Result: 5~n", result(5)).

显然,函数 result/1 的返回是原子 ok ,但我实际上想测试输出到控制台的字符串(即 "Result: 5~n" )。

我对这种方法有错吗,因为似乎没有其他人这样做(从我缺乏搜索结果来看)?

背景:第三方代码是一个交互式控制台应用程序,所以所有功能只使用 io:format显示结果。

最佳答案

方法一:使用meck

这段代码,经过测试,应该完全符合您的要求。它做了一些相当高级的技巧(特别是当它调用 meck:passthrough/0 时),但我认为它仍然很清楚。

% UUT
foo() ->
io:format("Look ma no newlines"),
io:format("more ~w~n", [difficult]),
io:format("~p dudes enter a bar~n", [3]),
ok.

% Helper: return true if mock Mod:Fun returned Result at least once.
meck_returned(Mod, Fun, Result) ->
meck_returned2(Mod, Fun, Result, meck:history(Mod)).

meck_returned2(_Mod, _Fun, _Result, _History = []) ->
false;
meck_returned2(Mod, Fun, Result, _History = [H|T]) ->
case H of
{_CallerPid, {Mod, Fun, _Args}, MaybeResult} ->
case lists:flatten(MaybeResult) of
Result -> true;
_ -> meck_returned2(Mod, Fun, Result, T)
end;
_ -> meck_returned2(Mod, Fun, Result, T)
end.

simple_test() ->
% Two concepts to understand:
% 1. we cannot mock io, we have to mock io_lib
% 2. in the expect, we use passthrough/0 to actually get the output
% we will be looking for in the history! :-)
ok = meck:new(io_lib, [unstick, passthrough]),
meck:expect(io_lib, format, 2, meck:passthrough()),
?assertMatch(ok, foo()),
%?debugFmt("history: ~p", [meck:history(io_lib)]),
?assert(meck_returned(io_lib, format, "Look ma no newlines")),
?assert(meck_returned(io_lib, format, "more difficult\n")),
?assert(meck_returned(io_lib, format, "3 dudes enter a bar\n")),
?assertNot(meck_returned(io_lib, format, "I didn't say this!")),
?assert(meck:validate(io_lib)).

方法二:使用 mock_io

最近(2017 年 5 月)我写了 mock_io ,通过实现 Erlang I/O 协议(protocol)来模拟被测单元的输入和输出的一种非常简单的方法。

使用 mock_io,等效代码变为:
% UUT
foo() ->
io:format("Look ma no newlines"),
io:format("more ~w~n", [difficult]),
io:format("~p dudes enter a bar~n", [3]),
ok.

simple_test() ->
Expected = <<"Look ma no newlines"
"more difficult\n",
"3 dudes enter a bar\n">>,
{Pid, GL} = mock_io:setup(),
?assertMatch(ok, foo()),
?assertEqual(Expected, mock_io:extract(Pid)),
mock_io:teardown({Pid, GL}).

另请注意,mock_io 允许在 UUT 输入 channel 中注入(inject)数据,无论是标准输入还是任何其他 channel 。例如:
% UUT
read_from_stdin() ->
io:get_line("prompt").

% Test
inject_to_stdin_test() ->
{IO, GL} = mock_io:setup(),
mock_io:inject(IO, <<"pizza pazza puzza\n">>),
?assertEqual("pizza pazza puzza\n", uut:read_from_stdin()),
?assertEqual(<<>>, mock_io:remaining_input(IO)),
mock_io:teardown({IO, GL}).

关于erlang - EUnit 和 io :format,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4334420/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com