mad*_*lep 17 parallel-processing concurrency erlang unit-testing
我在Erlang上花了一些时间,我想将TDD应用到我正在编写的代码中.
虽然标准库中的EUnit为测试常规样式代码提供了一个很好的传统单元测试框架,但似乎没有什么可以帮助测试并发代码,这在Erlang中使用了很多.
请注意,我们在这里讨论的是Erlang,它使用消息传递(而不是共享状态)来进行并发进程之间的通信,因此使用共享状态语言对并发代码进行单元测试的技术可能不适用.
有人找到了在Erlang中测试并发代码的好方法吗?
问题有点模糊("Erlang是并发的,用Erlang测试它!")但我会尝试详细说明一下.
测试Erlang代码的范围可以从简单直接(正确的输入产生正确的输出)到设置复杂的测试工具,以验证组件的行为方式.什么是最适合您的具体情况完全取决于您的要求和您想要做的黑盒子/白盒测试的数量.
Erlang的部分优点是能够使并发透明.请考虑以下示例(并行化列表列表总和的函数):
deep_sum(ListOfLists) ->
Parent = self(),
[spawn(fun() -> Parent ! lists:sum(List) end) || List <- ListOfLists],
lists:sum([receive Sum -> Sum end || _ <- ListOfLists]).
Run Code Online (Sandbox Code Playgroud)
您通常会使用一个非常简单的EUnit测试用例来测试它:
deep_sum_test() ->
?assertEqual(0, deep_sum([0, 0, 0, 0])),
?assertEqual(40, deep_sum([10, 10, 10, 10]).
Run Code Online (Sandbox Code Playgroud)
现在,假设我们对此功能有一些更明确的API:作为参数的进程池:
deep_sum(Pool, ListOfLists) ->
distribute_lists(Pool, ListOfLists),
lists:sum([receive Sum -> Sum end || _ <- ListOfLists]).
distribute_lists(Pool, ListOfLists) -> distribute_lists(Pool, Pool, ListOfLists).
distribute_lists([P|Pool], All, [L|ListOfLists]) ->
P ! {self(), L},
distribute_lists(Pool, All, ListOfLists);
distribute_lists([], All, ListOfLists) ->
distribute_lists(All, All, ListOfLists);
distribute_lists(_Pool, _All, []) ->
ok.
Run Code Online (Sandbox Code Playgroud)
在测试时,我们必须处理伪造这个进程池:
deep_sum_test() ->
Pool = [spawn_link(fun() -> fake_pool(1) end) || _ <- lists:seq(1, 3)],
?assertEqual(4, deep_sum(Pool, [lists:seq(1, 3) || _ <- list:seq(1, 4)]),
?assertEqual(7, deep_sum(Pool, [lists:seq(1, 3) || _ <- list:seq(1, 7)]),
[P ! stop || P <- Pool].
fake_pool(CannedResponse) ->
receive
{From, _L} -> From ! CannedResponse;
stop -> ok
end,
fake_pool(CannedResponse).
Run Code Online (Sandbox Code Playgroud)
如您所见,在Erlang中测试并发程序可以采用不同的形式.这些是非常简单的示例,但是使用Erlang内置的并发原语,可以非常轻松地创建所需的测试工具,并在适当的级别进行抽象.
我通常发现TDD与您正在测试并发代码是正交的,因此所述测试技术也可以用于正常的单元测试.
归档时间: |
|
查看次数: |
2323 次 |
最近记录: |