首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Mox模拟hackney

使用Mox模拟hackney
EN

Stack Overflow用户
提问于 2021-02-13 02:03:33
回答 2查看 303关注 0票数 1

我正在学习药剂和菲尼克斯堆栈,我被扔进了一个生产项目,使用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理解行为是什么,我理解错误,问题是,我不知道是否有一种方法“注入”行为定义给哈克尼进行这个模拟,或者我使用了错误的工具来完成这项工作。任何想法都是非常感谢的,谢谢:)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-02-16 19:58:13

埃弗雷特建议可能是您应该遵循的--特别是因为Mox在Elixir中非常流行。

但是,如果您有时间,我建议您查看Erlang的模拟库梅克。它不需要显式的契约/行为,您也可以模拟不存在的函数,这在TDD中很有用。有了梅克,你就会这样嘲笑哈克尼:

代码语言:javascript
复制
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模块和函数。

票数 4
EN

Stack Overflow用户

发布于 2021-02-14 02:12:50

我将与您分享一种方法,当第三方库不定义自己的行为时,我会使用Mox来模拟各种第三方库。

First:定义了您自己的Elixir行为,它定义了对应于您从库中使用的函数的回调。例如,如果您正在调用:hackney.get/2,那么在该函数的行为中定义一个回调。定义代码中可能没有实际使用的行为似乎毫无意义,但它为您做了两件重要的事情:

  1. 它帮助您记录您从给定模块中使用的函数,因此它是对该功能进行抽象的第一步(想象一下,如果突然不得不交换所使用的HTTP客户端库,您可能需要如何重构)。
  2. 它满足了Mox的需要,它可以通过反射来检查行为。

例如。

代码语言:javascript
复制
defmodule MyClientBehaviour do
  @callback get(url :: binary()) :: {:ok, any()} | {:error, any()}
end

注意,如果test/目录确实只用于测试,则可以定义它的行为。

第二步:调整您想要测试的代码,以便您可以在运行时提供模块。有两种常见的方法可以做到这一点:

  1. 通过提供的opt
  2. 从配置中解析模块。

例如,如果您的代码正在使用:hackney进行调用,例如

代码语言:javascript
复制
def get(url, opts \\ []) do
    :hackney.get(url)
end

您可以为重写提供一个选项,例如:

代码语言:javascript
复制
def get(url, opts \\ []) do
    client = Keyword.get(opts, :client, :hackney)
    client.get(url)
end

这样,您可以保留默认的实现(在您的情况下是:hackney),现在您可以在测试期间传递模拟。通常,您的test_helper.exs将声明正在使用的模拟。

代码语言:javascript
复制
# test_helper.exs
ExUnit.start()

Mox.Server.start_link([])

Mox.defmock(HTTPClientMock, for: MyClientBehaviour)
代码语言:javascript
复制
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注入,那么将其定义为一个可配置的模块是很有用的。

代码语言:javascript
复制
def get(url, opts \\ []) do
    client = Application.get_env(:my_app, :http_client, :hackney)
    client.get(url)
end

在本例中,您可以在运行测试之前将该值放在Application中(也可以将其添加到test.exs配置中)。这最好在setup块中完成,以确保在测试之前完成,并确保在测试完成时将其设置回原来的位置。

代码语言:javascript
复制
setup do
    http_client = Application.get_env(:my_app, :http_client)

    on_exit(fn ->
      Application.put_env(:my_app, :http_client, http_client)
    end)
end
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66181227

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档