我正在学习药剂和菲尼克斯堆栈,我被扔进了一个生产项目,使用Hackney模块(erlang)进行http调用。这里的情况是,我想Mock hackney的“请求”函数,所以当它被调用时,它会返回一个特定的响应。到目前为止,我已经跑到了Mox库上来实现这个目标,但是由于hackney是一个Erlang模块,并且Mox抱怨它不是一种行为,我想知道是否有更好的方法来做到这一点,或者可能还有另一个缺少的配置。代码失败的地方是在模拟定义的开始阶段:
Mox.defmock(MyApp.MockHackney, for: :hackney) --这在module :hackney is not a behaviour, please pass a behaviour to :for中失败了
我假设我做错了什么(我在这里跟踪Mox库的文档:https://hexdocs.pm/mox/Mox.html理解行为是什么,我理解错误,问题是,我不知道是否有一种方法“注入”行为定义给哈克尼进行这个模拟,或者我使用了错误的工具来完成这项工作。任何想法都是非常感谢的,谢谢:)
发布于 2021-02-16 19:58:13
埃弗雷特建议可能是您应该遵循的--特别是因为Mox在Elixir中非常流行。
但是,如果您有时间,我建议您查看Erlang的模拟库梅克。它不需要显式的契约/行为,您也可以模拟不存在的函数,这在TDD中很有用。有了梅克,你就会这样嘲笑哈克尼:
setup do
:ok = :meck.new(:hackney)
:ok = :meck.expect(:hackney, :get, fn "url" -> :ok end)
on_exit(fn ->
:meck.unload(:hackney)
end)
end
test "mocked hackney request" do
result = :hackney.get("url")
assert result == :ok
end当然,它还支持模拟Elixir模块和函数。
发布于 2021-02-14 02:12:50
我将与您分享一种方法,当第三方库不定义自己的行为时,我会使用Mox来模拟各种第三方库。
First:定义了您自己的Elixir行为,它定义了对应于您从库中使用的函数的回调。例如,如果您正在调用:hackney.get/2,那么在该函数的行为中定义一个回调。定义代码中可能没有实际使用的行为似乎毫无意义,但它为您做了两件重要的事情:
例如。
defmodule MyClientBehaviour do
@callback get(url :: binary()) :: {:ok, any()} | {:error, any()}
end注意,如果test/目录确实只用于测试,则可以定义它的行为。
第二步:调整您想要测试的代码,以便您可以在运行时提供模块。有两种常见的方法可以做到这一点:
opt或例如,如果您的代码正在使用:hackney进行调用,例如
def get(url, opts \\ []) do
:hackney.get(url)
end您可以为重写提供一个选项,例如:
def get(url, opts \\ []) do
client = Keyword.get(opts, :client, :hackney)
client.get(url)
end这样,您可以保留默认的实现(在您的情况下是:hackney),现在您可以在测试期间传递模拟。通常,您的test_helper.exs将声明正在使用的模拟。
# test_helper.exs
ExUnit.start()
Mox.Server.start_link([])
Mox.defmock(HTTPClientMock, for: MyClientBehaviour)defmodule YourTest do
use ExUnit.Case
import Mox
setup :verify_on_exit!
test ":ok something" do
client =
HTTPClientMock
|> expect(:get, fn _ ->
{:ok, "some response here"}
end)
assert {:ok, _} = YourModule.get("http://example.com", client: client)
end
end如果调用:hackey的地方太深,不允许进行opts注入,那么将其定义为一个可配置的模块是很有用的。
def get(url, opts \\ []) do
client = Application.get_env(:my_app, :http_client, :hackney)
client.get(url)
end在本例中,您可以在运行测试之前将该值放在Application中(也可以将其添加到test.exs配置中)。这最好在setup块中完成,以确保在测试之前完成,并确保在测试完成时将其设置回原来的位置。
setup do
http_client = Application.get_env(:my_app, :http_client)
on_exit(fn ->
Application.put_env(:my_app, :http_client, http_client)
end)
endhttps://stackoverflow.com/questions/66181227
复制相似问题