Erlang Common Test测试中终止gen_server不触发用例失败的求助
问题根因分析
- 代码逻辑不匹配:
kill()函数发送的是同步gen_server:call请求,但对应的处理函数写的是handle_cast,且handle_cast里错误使用了reply语法(仅handle_call支持返回reply)
- 代码逻辑不匹配:
- 同步调用抛出未捕获异常:当gen_server处理call请求时返回
{stop, killed, State},gen_server会终止并给调用方返回exit异常,测试进程没有捕获这个异常就会直接崩溃,导致测试用例失败
- 同步调用抛出未捕获异常:当gen_server处理call请求时返回
- 之前
trap_exit不生效的原因:gen_server:call抛出的是调用异常,不是进程链接的exit信号,trap_exit仅能捕获当前进程收到的链接进程退出信号,管不到call调用本身抛出的异常。
- 之前
可行解决方案
方案1:改用异步cast触发崩溃(推荐,改动最小)
直接修改mod_bad_process的代码,把同步调用改成异步,不会给测试进程返回异常:
- 修正kill函数实现:
kill() -> gen_server:cast(?MODULE, {update_behavior, kill}).
- 修正handle_cast的语法错误:
handle_cast({update_behavior, Behavior}, State) -> case Behavior of kill -> {stop, killed, State}; _ -> {noreply, State#{state := Behavior}} end;
测试代码不需要改,调用mod_bad_process:kill()后会立刻返回,不会抛出异常。
方案2:捕获call调用的异常(不需要修改被测模块代码)
如果不能改动mod_bad_process的实现,就在测试代码里调用kill的时候显式捕获exit异常,同时可以优化等待逻辑避免硬编码延迟:
remonitor_test(_Conf) -> InitialPid = whereis(?BAD_PROC), true = undefined =/= InitialPid, true = is_monitored_gen_server(?BAD_PROC), % 捕获kill调用抛出的exit异常 try mod_bad_process:kill() catch exit:{killed, _} -> ok end, % 替换timer:sleep为主动等待进程退出,避免等待时间不足导致用例不稳定 monitor(process, InitialPid), receive {'DOWN', _, process, InitialPid, killed} -> ok after ?REMONITOR_DELAY_MS -> error({wait_process_kill_timeout, InitialPid}) end, FinalPid = whereis(?BAD_PROC), true = InitialPid =/= FinalPid, true = undefined =/= FinalPid, true = is_monitored_gen_server(?BAD_PROC).
方案3:单独开临时进程执行kill操作
如果不想处理异常,也可以派生一个临时进程调用kill,临时进程崩溃不会影响测试主进程:
% 测试代码中替换原有kill调用 spawn(fun() -> mod_bad_process:kill() end),
内容的提问来源于stack exchange,提问作者Josh K
相关产品推荐
相关产品推荐

