Testing 如何在GenServer中正确测试handle_cast?

Testing 如何在GenServer中正确测试handle_cast?,testing,erlang,elixir,otp,gen-server,Testing,Erlang,Elixir,Otp,Gen Server,我有一个GenServer,负责联系外部资源。调用外部资源的结果并不重要,任何时候的失败都是可以接受的,因此使用handle\u cast似乎适用于代码的其他部分。对于外部资源,我确实有一个类似于模块的接口,我使用一个GenServer来访问资源。到目前为止还不错 但是当我试图为这个gen_服务器编写测试时,我不知道如何测试句柄\u cast。我为GenServer提供了接口函数,并尝试测试这些函数,但它们总是返回:ok,除非GenServer未运行。我无法测试这一点 我稍微修改了一下代码。我将

我有一个GenServer,负责联系外部资源。调用外部资源的结果并不重要,任何时候的失败都是可以接受的,因此使用
handle\u cast
似乎适用于代码的其他部分。对于外部资源,我确实有一个类似于模块的接口,我使用一个GenServer来访问资源。到目前为止还不错

但是当我试图为这个gen_服务器编写测试时,我不知道如何测试
句柄\u cast
。我为GenServer提供了接口函数,并尝试测试这些函数,但它们总是返回
:ok
,除非GenServer未运行。我无法测试这一点

我稍微修改了一下代码。我将
handle\u cast
中的代码抽象到另一个函数中,并创建了一个类似的
handle\u调用
回调。然后我就可以很容易地测试
处理你的电话了,但那是一种黑客行为


我想知道人们通常是如何测试异步代码的。我的方法是正确的,还是可以接受的?如果没有,该怎么办?

诀窍是记住GenServer进程按顺序逐个处理消息。这意味着我们可以通过确保进程处理了我们稍后发送的消息来确保它接收并处理了一条消息。这反过来意味着我们可以将任何异步操作更改为同步操作,方法是在其后面添加同步消息,例如某个调用

测试场景如下所示:

  • 发出异步请求
  • 发出同步请求并等待结果
  • 断言异步请求的效果
  • 如果服务器没有任何合适的同步功能,您可以考虑使用<代码>:sys .GETYSTATE/2 ——一个用于调试目的的调用,它被所有特殊进程(包括GEnServer)正确处理,并且可能是最重要的事情,同步。我认为使用它来测试是完全有效的。< /P>


    您可以从中的
    :sys
    模块中阅读有关其他有用函数的更多信息。

    强制转换请求的形式如下:

    Module:handle_cast(Request, State) -> Result
    
    Types:
    Request = term()
    State = term()
    Result = {noreply,NewState} | 
             {noreply,NewState,Timeout} | 
             {noreply,NewState,hibernate} |
             {stop,Reason,NewState}
    NewState = term()
    Timeout = int()>=0 | infinity 
    Reason = term()
    
    因此,只需直接调用单元测试(甚至不需要启动服务器),提供
    请求和
    状态,并断言返回的
    结果,就可以很容易地执行单元测试。当然,它也可能有一些副作用(如写入ets表、修改流程字典等),因此您需要在断言之前初始化这些资源,并在断言之后检查效果

    例如:

    test_add() ->
        {noreply,15} = my_counter:handle_cast({add,5},10).
    

    您想在这里的
    handle\u cast
    中测试什么?是否能够与外部资源进行初步接触?还是说它也成功了?是否希望在每次测试运行期间实际联系该外部资源?(一些粗略的代码大纲也会有帮助。)不,我将外部资源接口模块注入GenServer,所以我不想实际联系资源(这将花费我的钱)。由于
    handle\u cast
    使用接口模块的一些函数,我想测试当函数返回okayish值时它是否成功。添加一些代码是一个好主意,我今天会在几个小时内完成。要点1和2。但第三个有点不清楚,一个如何测试在另一个过程中正在进行的一些效果?这些病例似乎没有通用的治疗方法,因为每个病例都可能有副作用,也可能没有副作用。即使有,也可能有基本不同的,因此断言也会不同。在我的例子中,似乎是正确的解决方案,我的接口函数只是充当
    handle.*
    函数的委托。IDK介绍了具有更复杂接口函数的其他用例,但这将解决我的问题。谢谢