我有一台GenServer,它负责联系外部资源。调用外部资源的结果并不重要,有时可能会出现失败,因此使用handle_cast
似乎适用于代码的其他部分。我确实有一个类似于接口的模块用于该外部资源,我正在使用一个GenServer来访问该资源。到目前为止一切都很好。
但是当我尝试为这个gen_server编写测试时,我无法弄清楚如何测试handle_cast
。我有GenServer的接口函数,我尝试测试那些,但它们总是返回:ok
,除非GenServer没有运行。我无法测试。
我稍微更改了代码。我将handle_cast
中的代码抽象为另一个函数,并创建了类似的handle_call
回调。然后我可以轻松地测试handle_call
,但这有点像黑客。
我想知道人们通常如何测试异步代码。我的方法是正确的还是可接受的?如果没有,那该怎么办?
答案 0 :(得分:2)
诀窍是要记住GenServer进程按顺序逐个处理消息。这意味着我们可以确保处理收到并处理了一条消息,确保它处理了我们稍后发送的消息。这反过来意味着我们可以通过跟随同步消息(例如一些调用)将任何异步操作更改为同步操作。
测试场景如下所示:
如果服务器没有任何合适的同步功能,您可以考虑使用:sys.get_state/2
- 一个用于调试目的的调用,由所有特殊进程(包括GenServer)正确处理,并且可能是最重要的是,同步。我认为用它进行测试是完全有效的。
:sys
模块中详细了解其他有用的功能
答案 1 :(得分:2)
投射请求的格式为:
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
,并声明返回的Result
。当然它也可能有一些副作用(比如在ets表中编写,修改进程字典......)所以你需要在之前初始化这些资源,并在断言后检查效果。
例如:
test_add() ->
{noreply,15} = my_counter:handle_cast({add,5},10).