我想测试一个使用Task.async
为了让我的测试通过,我需要在断言前让它休眠100ms,否则测试过程会在执行异步任务之前被终止。
有更好的方法吗?
已编辑,添加代码示例:
我想测试的代码(大致):
def search(params) do
RateLimiter.rate_limit(fn ->
parsed_params = ExTwitter.Parser.parse_request_params(params)
json = ExTwitter.API.Base.request(:get, "1.1/search/tweets.json", parsed_params)
Task.async(fn -> process_search_output(json) end)
new_max_id(json)
end)
end
我已经写过的测试(仅与睡眠呼叫一起工作)
test "processes and store tweets" do
with_mock ExTwitter.API.Base, [request: fn(_,_,_) -> json_fixture end] do
with_mock TwitterRateLimiter, [rate_limit: fn(fun) -> fun.() end] do
TSearch.search([q: "my query"])
:timer.sleep(100)
# assertions
assert called TStore.store("some tweet from my fixtures")
assert called TStore.store("another one")
end
end
end
答案 0 :(得分:35)
由于问题有点模糊,我将在此给出一般答案。通常的技术是监视进程并等待关闭消息。像这样:
task = Task.async(fn -> "foo" end)
ref = Process.monitor(task.pid)
assert_receive {:DOWN, ^ref, :process, _, :normal}, 500
一些重要的事情:
元组的第五个元素是退出原因。我断言任务出口是:normal
。如果您希望再次退出,请相应地更改。
assert_receive
中的第二个值是超时。鉴于您目前有100毫秒的睡眠时间,500毫秒听起来是合理的数量。
答案 1 :(得分:9)
当我无法使用José的assert_receive
方法时,我会使用一个小助手重复执行断言/睡眠,直到断言通过或最后超时。
这是辅助模块
defmodule TimeHelper do
def wait_until(fun), do: wait_until(500, fun)
def wait_until(0, fun), do: fun.()
def wait_until(timeout, fun) defo
try do
fun.()
rescue
ExUnit.AssertionError ->
:timer.sleep(10)
wait_until(max(0, timeout - 10), fun)
end
end
end
在前面的示例中可以像这样使用:
TSearch.search([q: "my query"])
wait_until fn ->
assert called TStore.store("some tweet from my fixtures")
assert called TStore.store("another one")
end