我正在尝试为我的一种行为创建一个模拟。为此,我使用 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
是库中的东西,但我找不到它。
原来我的问题是我在应用程序启动时引用了
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
或类似的东西中。请参阅此处的文档:Mox — Mox v1.1.0test/support/mocks.ex
这表明有一种编译时方法也可以解决这个问题。 原帖:https://elixirforum.com/t/how-to-test-a-phoenix-controller-with-hammox/64191/5?u=fl4m3ph03n1x