You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Erlang Common Test测试中终止gen_server不触发用例失败的求助

问题根因分析
    1. 代码逻辑不匹配:kill()函数发送的是同步gen_server:call请求,但对应的处理函数写的是handle_cast,且handle_cast里错误使用了reply语法(仅handle_call支持返回reply)
    1. 同步调用抛出未捕获异常:当gen_server处理call请求时返回{stop, killed, State},gen_server会终止并给调用方返回exit异常,测试进程没有捕获这个异常就会直接崩溃,导致测试用例失败
    1. 之前trap_exit不生效的原因:gen_server:call抛出的是调用异常,不是进程链接的exit信号,trap_exit仅能捕获当前进程收到的链接进程退出信号,管不到call调用本身抛出的异常。
可行解决方案

方案1:改用异步cast触发崩溃(推荐,改动最小)

直接修改mod_bad_process的代码,把同步调用改成异步,不会给测试进程返回异常:

  1. 修正kill函数实现:
kill() ->
    gen_server:cast(?MODULE, {update_behavior, kill}).
  1. 修正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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 13:51:04