如何使用 Hammox 测试 Phoenix 控制器?

问题描述 投票:0回答:1

背景

我正在尝试为我的一种行为创建一个模拟。为此,我使用 Hammox(Mox 的变体,扩展了 api)。

我已经设置了我的应用程序,以便它从配置文件中获取要使用的模块,在本例中

config/test.exs

config/test.exs

config :my_app, storage: StorageMock

这是测试文件:

test/my_app/application_test.exs

defmodule MyApp.ApplicationTest do
  @moduledoc false

  use ExUnit.Case, async: false
  use MyApp.ConnCase

  import Hammox

  test "client can handle an error response", %{conn: conn} do
    Hammox.defmock(StorageMock, for: MyApp.Storage)

    expect(StorageMock, :get, fn args ->
      assert args == "Chicago"

      # here we decide what the mock returns
      {:ok, %{body: "Some html with weather data"}}
    end)

    get(conn, "~p/api/users/validate")
  end
end

我正在尝试测试控制器的端点,我基本上将 Hammox 的文档(https://github.com/msz/hammox)与我从测试控制器指南(https:// hexdocs.pm/phoenix/testing_controllers.html#content).

问题

不幸的是,我认为我的设置不正确,因为我收到此错误:

Compiling 1 file (.ex)
** (Mix) Could not start application my_app: exited in: MyApp.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (ArgumentError) The module StorageMock was given as a child to a supervisor but it does not exist
            (elixir 1.16.0) lib/supervisor.ex:797: Supervisor.init_child/1
            (elixir 1.16.0) lib/enum.ex:1700: Enum."-map/2-lists^map/1-1-"/2
            (elixir 1.16.0) lib/enum.ex:1700: Enum."-map/2-lists^map/1-1-"/2
            (elixir 1.16.0) lib/supervisor.ex:783: Supervisor.init/2
            (elixir 1.16.0) lib/supervisor.ex:707: Supervisor.start_link/2
            (kernel 9.2) application_master.erl:293: :application_master.start_it_old/4

我在这里缺少什么? 我假设某个地方有一些配置可以告诉虚拟机

StorageMock
是库中的东西,但我找不到它。

testing controller elixir phoenix-live-view
1个回答
0
投票

我的解决方案

原来我的问题是我在应用程序启动时引用了

StorageMock
,即:

defmodule MyApp.Application do
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
   children = 
    [
      MyAppWeb.Telemetry,
      {Phoenix.PubSub, name: MyApp.PubSub},
      {StorageMock, []},
      MyAppWeb.Endpoint
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

通过从子级列表中删除

StorageMock
(运行测试时),错误得到修复。

对于那些好奇的人,您可以使用

Mix.env()
检查应用程序正在哪个环境中运行。因此,你可以这样做:

  def start(_type, _args) do
    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children(Mix.env(), opts)
  end

  defp children(:test) do
    [
      MyAppWeb.Telemetry,
      {Phoenix.PubSub, name: MyApp.PubSub},
      MyAppWeb.Endpoint
    ]
  end

  defp children(_other_envs) do
    [
      MyAppWeb.Telemetry,
      {Phoenix.PubSub, name: MyApp.PubSub},
      {RealStorage, ["localhost:5221"]},
      MyAppWeb.Endpoint
    ]
  end

这是我最终采用的解决方案,因为这意味着您可以使用

config/test.exs
来定义要使用的模块。如果您愿意的话,您甚至可以使用
Application.put_env/3
在运行时更改模块,这在进行某些特定类型的测试时也可以派上用场。

其他方法

另一种可行的方法可以在社区的评论中看到:

test_helper.exs
也会在应用程序启动后加载。有效的方法是将
defmock
放入已编译的文件(而不是脚本)中,例如在
test/support/mocks.ex
或类似的东西中。请参阅此处的文档:Mox — Mox v1.1.0

这表明有一种编译时方法也可以解决这个问题。 原帖:https://elixirforum.com/t/how-to-test-a-phoenix-controller-with-hammox/64191/5?u=fl4m3ph03n1x

© www.soinside.com 2019 - 2024. All rights reserved.