对于在Elixir中实现Genserver来说,我还很陌生。我有一种情况,我正在尝试管理某些状态,Genserver在这种情况下工作得很好。但是,在测试Genserver时,我遇到了一些麻烦。
我有两个测试似乎相互碰撞。我对我的Genserver进行了单元级测试,对更高级别的测试进行了调用,该函数调用的功能是将Genserver与模块一起使用。这是我的两个测试用例:
defmodule MyApp.ScoreTableQueueTest do
use MyApp.DataCase
alias MyApp.{ScoreTableQueue}
setup do
start_supervised(ScoreTableQueue)
:ok
end
test "pushes value in the queue" do
assert :ok == ScoreTableQueue.push([1,2,3,4])
end
test "pops the full value of the queue" do
assert [[1,2,3,4]] == ScoreTableQueue.pop()
end
end
如果我单独运行此命令,则每次都会通过。但是,如果我运行此测试,它将定期中断:
setup do
start_supervised(ScoreTableQueue)
:ok
end
describe "distribute" do
test "it distrbutes the correct season points" do
{:ok, table} = List.first(MyApp.ScoreTableAllocator.distribute())
assert table.table_details.information == [
%{team_id: team_3.id, team_score: "N/A"},
%{team_id: team_2.id, team_score: ps_2.score},
%{team_id: team_1.id, team_score: ps_1.score}
]
assert table.question_id == question.id
assert table.season_id == season.id
end
end
实际上,在我的distribute/1
函数中使用了Genserver。如果我单独调用此测试,则每次都能正常运行。但是,当我一起运行测试时,似乎花了一半的时间,使我相信我正在启动同一台服务器,并在两次测试之间将信息传递到同一台服务器。
我的问题:如何将每个测试彼此分开?我希望每种测试的每种情况(至少每个文件)都具有完全不同的服务器。 Elixir的方法是什么?
答案 0 :(得分:1)
在这种情况下,我建议修改模块的API函数以接受要使用的服务器,默认情况下使用全局实例。遵循以下原则:
defmodule MyApp.ScoreTableQueue do
use GenServer
def push(server \\ __MODULE__, item) do
GenServer.call(server, {:push, item})
end
...
end
然后在测试中,您只需为每个测试启动一个实例:
setup do
{:ok, pid} = GenServer.start_link(MyApp.ScoreTableQueue, _init_args = nil)
{:ok, queue: pid}
end
test "pushes value in the queue", %{queue: queue} do
assert :ok == ScoreTableQueue.push(queue, [1,2,3,4])
end
当您开始使用start_supervised
时,它是根据模块中的child_spec
函数启动的-我假设它指定了服务器的全局实例,因此这两个测试很可能会干扰每个其他。
另一个选择是将测试设置为同步(通过使用use MyApp.DataCase, async: false
),以使它们永远不会同时运行。这可能甚至更简单,但是如果测试套件很大,则速度可能会变慢。