Elixir/Phoenix GraphQL订阅测试ChannelCase配置报错求助
问题解决:Elixir GraphQL订阅测试中Phoenix.ChannelTest.connect宏错误
问题背景
Elixir项目中实现的created_user GraphQL订阅在localhost:4000/graphiql运行正常,但编写单元测试时,自定义的ChannelCase和SubscriptionCase导致测试抛出UndefinedFunctionError,提示Phoenix.ChannelTest.connect/2是宏需require,尝试替换为import仍无效。
错误原因
- 宏调用上下文错误:
Phoenix.ChannelTest.connect/2是宏,ChannelCase的setup块直接在模块上下文调用该宏,但未在ChannelCase模块内require对应宏模块。 - SubscriptionCase重复配置:
SubscriptionCase中同时use ChannelCase又自行定义setup,不仅冗余还出现参数错误(错误传递Endpoint给connect,应该传UserSocket)。 - 依赖注入重复:重复导入/使用
Phoenix.ChannelTest和Absinthe.Phoenix.SubscriptionTest,导致上下文混乱。
修复方案
1. 修正ChannelCase配置
在ChannelCase模块内require Phoenix.ChannelTest,确保宏能被正确调用,同时保留原有沙箱配置:
defmodule GraphqlUserWeb.ChannelCase do use ExUnit.CaseTemplate # 在此处require宏模块,确保setup块能调用connect宏 require Phoenix.ChannelTest using do quote do use Phoenix.ChannelTest import Absinthe.Phoenix.SubscriptionTest @endpoint GraphqlUserWeb.Endpoint end end setup tags do :ok = Ecto.Adapters.SQL.Sandbox.checkout(GraphqlUser.Repo) unless tags[:async] do Ecto.Adapters.SQL.Sandbox.mode(GraphqlUser.Repo, {:shared, self()}) end # 直接调用宏,此时已require {:ok, socket} = Phoenix.ChannelTest.connect(GraphqlUserWeb.UserSocket, %{}) {:ok, socket: Absinthe.Phoenix.SubscriptionTest.join_absinthe(socket)} end end
2. 简化SubscriptionCase配置
移除重复的setup和冗余导入,直接复用ChannelCase的配置:
defmodule GraphqlUserWeb.SubscriptionCase do use ExUnit.CaseTemplate using do quote do use GraphqlUserWeb.ChannelCase use Absinthe.Phoenix.SubscriptionTest, schema: GraphqlUserWeb.Schema # 无需重复定义setup,ChannelCase已提供socket end end end
3. 调整测试代码(优化验证逻辑)
确保测试逻辑完整,订阅后触发事件验证接收:
defmodule GraphqlUserWeb.SubscriptionTest do use GraphqlUserWeb.SubscriptionCase alias GraphqlUser.Factory describe "user subscriptions" do test "receives a created_user subscription event", %{socket: socket} do # 订阅createdUser ref = push_doc(socket, """ subscription { createdUser { id name email } } """) assert_reply ref, :ok, %{subscriptionId: _subscription_id} # 创建用户触发订阅事件 user = Factory.insert(:user) Absinthe.Subscription.publish(GraphqlUserWeb.Endpoint, user, created_user: "new_user") # 验证接收事件 assert_push "subscription:data", %{result: %{data: %{"createdUser" => received_user}}} assert received_user["id"] == to_string(user.id) assert received_user["name"] == user.name assert received_user["email"] == user.email end end end
关键说明
- 宏必须在调用它的上下文被
require,using块中的导入只作用于测试模块,不作用于ChannelCase自身的setup块。 SubscriptionCase无需重复实现setup,复用ChannelCase的配置即可避免冗余和错误。- 测试中需主动触发订阅事件(通过
Absinthe.Subscription.publish),才能验证订阅是否正常接收消息。
内容的提问来源于stack exchange,提问作者jl118
相关产品推荐
相关产品推荐

