如何在 GenServer 中正确测试 handle_cast?
How to test handle_cast in a GenServer properly?
我有一个GenServer,负责联系外部资源。调用外部资源的结果并不重要,偶尔失败是可以接受的,所以使用 handle_cast
似乎适用于代码的其他部分。我确实有一个用于该外部资源的类似接口的模块,并且我正在使用一个 GenServer 来访问该资源。到目前为止一切顺利。
但是当我尝试为此 gen_server 编写测试时,我不知道如何测试 handle_cast
。我有 GenServer 的接口函数,我试图测试那些,但它们总是 return :ok
,除非 GenServer 不是 运行。我无法测试。
我稍微更改了代码。我将 handle_cast
中的代码抽象为另一个函数,并创建了一个类似的 handle_call
回调。然后我可以轻松地测试 handle_call
,但那是一种 hack。
我想知道人们通常如何测试异步代码,就像那样。我的方法是否正确或可以接受?如果没有,那怎么办?
诀窍是记住 GenServer 进程按顺序一条一条地处理消息。这意味着我们可以确保进程接收并处理了消息,方法是确保它处理了我们稍后发送的消息。这反过来意味着我们可以将任何异步操作更改为同步操作,方法是在它后面加上同步消息,例如一些调用。
测试场景如下所示:
- 发出异步请求。
- 发出同步请求,等待结果
- 断言异步请求的效果。
如果服务器没有任何合适的同步功能,您可以考虑使用 :sys.get_state/2
- 一个用于调试目的的调用,由所有特殊进程(包括 GenServer)正确处理,并且是,什么可能是最重要的事情,同步。我认为将它用于测试是完全有效的。
您可以从 GenServer documentation on debugging 中的 :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()
因此执行单元测试非常容易,只需直接调用它(甚至不需要启动服务器),提供一个 Request
和一个 State
,并断言返回的 [=14] =].当然它也可能有一些副作用(比如写一个etstable,修改process dictionary...)所以你需要先初始化那些资源,assert后检查效果。
例如:
test_add() ->
{noreply,15} = my_counter:handle_cast({add,5},10).
我有一个GenServer,负责联系外部资源。调用外部资源的结果并不重要,偶尔失败是可以接受的,所以使用 handle_cast
似乎适用于代码的其他部分。我确实有一个用于该外部资源的类似接口的模块,并且我正在使用一个 GenServer 来访问该资源。到目前为止一切顺利。
但是当我尝试为此 gen_server 编写测试时,我不知道如何测试 handle_cast
。我有 GenServer 的接口函数,我试图测试那些,但它们总是 return :ok
,除非 GenServer 不是 运行。我无法测试。
我稍微更改了代码。我将 handle_cast
中的代码抽象为另一个函数,并创建了一个类似的 handle_call
回调。然后我可以轻松地测试 handle_call
,但那是一种 hack。
我想知道人们通常如何测试异步代码,就像那样。我的方法是否正确或可以接受?如果没有,那怎么办?
诀窍是记住 GenServer 进程按顺序一条一条地处理消息。这意味着我们可以确保进程接收并处理了消息,方法是确保它处理了我们稍后发送的消息。这反过来意味着我们可以将任何异步操作更改为同步操作,方法是在它后面加上同步消息,例如一些调用。
测试场景如下所示:
- 发出异步请求。
- 发出同步请求,等待结果
- 断言异步请求的效果。
如果服务器没有任何合适的同步功能,您可以考虑使用 :sys.get_state/2
- 一个用于调试目的的调用,由所有特殊进程(包括 GenServer)正确处理,并且是,什么可能是最重要的事情,同步。我认为将它用于测试是完全有效的。
您可以从 GenServer documentation on debugging 中的 :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()
因此执行单元测试非常容易,只需直接调用它(甚至不需要启动服务器),提供一个 Request
和一个 State
,并断言返回的 [=14] =].当然它也可能有一些副作用(比如写一个etstable,修改process dictionary...)所以你需要先初始化那些资源,assert后检查效果。
例如:
test_add() ->
{noreply,15} = my_counter:handle_cast({add,5},10).