我如何在单元测试中写下期望?
以下是一个例子:
defmodule MyAPIModule do
@url "http://example.com/path"
def get_something(http_module \\ HTTPoison) do
http_module.get!(@url, [], [])
end
end
这是我的测试:
defmodule MyAPIModuleTest do
use ExUnit.Case
test "Runs the get! method with no headers and no params" do
MyAPIModule.get_something(HttpSpy)
# 1) assert that get! was called
# 2) assert [] == headers
# 3) assert [] == params
# 4) assert "http://example.com/path" == url
end
end
defmodule HttpSpy do
def get!(url, headers, params) do
#
end
end
我的问题是不变性。我不能简单地在HttpSpy模块中创建一个列表,并将方法调用及其参数记录到该列表中。
所以我尝试用这种方式改变HttpSpy:
defmodule HttpSpy do
def start(listener) do
spawn_link(__MODULE__, loop, [listener])
end
def loop(listener) do
receive do
end
end
def get!(url, headers, params) do
end
end
我将测试更改为:
test "Runs the get! method with no headers and no params"
spy = HttpSpy.start(self)
MyAPIModule.get_something(HttpSpy)
receive do
{^spy, method_call} -> flunk("wrong method call")
after 1000 -> flunk("timeout")
end
end
但是我被困住了。 HttpSpy.get!不知道测试产生的HttpSpy过程的PID。
因此HttpSpy.get!无法向循环方法中等待的进程发送消息。
因此,循环方法永远不会向测试(我称之为监听器)发送被调用的函数及其参数。
我意识到我想要的基本上是模拟和期望,但我想找到惯用的方式(=没有嘲笑)来做它。
答案 0 :(得分:3)
# In the spy
send self(), :get_was_called
# In the test
assert_received :get_was_called
答案 1 :(得分:2)
您可以从假get!
函数返回所需的值,提取它们然后断言结果。您将隐式知道调用了正确的函数,因为它返回了预期的结果。
defmodule FakeHttp do
def get!(url, headers, params) do
{:get!, url, headers, params}
end
end
defmodule MyAPIModuleTest do
use ExUnit.Case
test "Runs the get! method with no headers and no params" do
{:get!, url, headers, params} =
MyAPIModule.get_something(FakeHttp)
assert [] == headers
assert [] == params
assert "http://example.com/path" == url
end
end
无论如何,我认为断言调用特定函数并不是最重要的事情。我认为对外部可见结果进行断言更有用。这样,只要新实现产生相同的结果,您就可以换出底层实现,并且您的测试仍会通过。