我正在制作多站点应用程序。我想在测试控制器之前在连接上设置请求主机。在Rails中,我们可以使用
执行此操作before :each do
request.env["HTTP_REFERER"] = '/'
end
有人可以建议如何在凤凰城做同样的事情吗?
编辑1 :我可以使用设置主机
conn |> put_req_header("host", "abc.com")
,但这并未更改host
对象中的conn
属性。它仍然指向“www.example.com”
编辑2 :我也尝试了
test "creates resource and redirects when data is valid", %{conn: _conn} do
struct_url = %{Myapp.Endpoint.struct_url | host: "abc.com"}
conn = post(conn, registration_url(struct_url, :create, user: @valid_attrs))
assert redirected_to(conn) == "/"
end
但是我收到了以下错误:
$ mix test test/controllers/registration_controller_test.exs 1) test creates resource and redirects when data is valid (Myapp.RegistrationControllerTest)
test/controllers/registration_controller_test.exs:14
** (RuntimeError) expected action/2 to return a Plug.Conn, all plugs must receive a connection (conn) and return a connection
stacktrace:
(myapp) web/controllers/registration_controller.ex:1: Myapp.RegistrationController.phoenix_controller_pipeline/2
(myapp) lib/phoenix/router.ex:255: Myapp.Router.dispatch/2
(myapp) web/router.ex:1: Myapp.Router.do_call/2
(myapp) lib/myapp/endpoint.ex:1: Myapp.Endpoint.phoenix_pipeline/1
(myapp) lib/phoenix/endpoint/render_errors.ex:34: Myapp.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:193: Phoenix.ConnTest.dispatch/5
test/controllers/registration_controller_test.exs:16
registration_controller.ex第1行是defmodule Myapp.RegistrationControllerTest do
编辑3 :
创建registration_controller.ex
def create(conn, %{"user" => user_params}) do
user_changeset = User.changeset(%User{}, user_params)
if user_changeset.valid? do
Repo.transaction fn ->
user = Repo.insert!(user_changeset)
user_site = Ecto.Model.build(user, :user_sites, site: site_id(conn))
Repo.insert!(user_site)
conn
|> put_flash(:info, "Your account was created")
|> put_session(:current_user, user)
|> redirect(to: "/")
end
else
conn
|> render("new.html", changeset: user_changeset)
end
end
答案 0 :(得分:8)
由于Plug.Conn
是结构,如果您需要更改主机,则可以使用map update syntax:
conn = %{conn | host: "abc.com"}
如果您想更改管道中的密钥,请使用Map.put/3:
conn =
conn()
|> put_header("content-type", "json")
|> Map.put(:host, "abc.com")
如果您想在每次测试前运行某些内容,可以使用ExUnit.Callbacks.setup/2
setup do
conn = %{conn() | host: "abc.com"}
{:ok, conn}
end
test "foo", %{conn: conn} do
get(conn, ...)
end
修改强>
您将看到主机由以下人员确定:
host: uri.host || "www.example.com"
的凤凰城中调用了哪个
这意味着为了获得您想要的主机,您需要在网址中指定它,而不是conn
试试这个:
struct_url = %{MyApp.Endpoint.struct_url | host: "abc.com"}
conn = get(conn, foo_url(struct_url, :index)) #note foo_url not foo_path
<强> EDIT2 强>
这里的问题是:
Repo.transaction fn ->
user = Repo.insert!(user_changeset)
user_site = Ecto.Model.build(user, :user_sites, site: site_id(conn))
Repo.insert!(user_site)
conn
|> put_flash(:info, "Your account was created")
|> put_session(:current_user, user)
|> redirect(to: "/")
end
错误告诉您action/2
应该返回Plug.Conn
但是您要返回transaction/3的结果({:ok, value}
或{error, value}
}
这意味着您的函数将返回{:ok, conn}
尝试:
Repo.transaction fn ->
user = Repo.insert!(user_changeset)
user_site = Ecto.Model.build(user, :user_sites, site: site_id(conn))
Repo.insert!(user_site)
end
conn
|> put_flash(:info, "Your account was created")
|> put_session(:current_user, user)
|> redirect(to: "/")
如果你想根据事务返回不同的结果,那么我会将整个部分移动到像AccountService.create
这样的模块函数,然后使用如下的case语句:
def create(conn, %{"user" => user_params}) do
case MessageService.create(user_params) do
{:ok, user} ->
|> put_flash(:info, "Your account was created")
|> put_session(:current_user, user)
|> redirect(to: "/")
{:error, changeset} ->
conn
|> render("new.html", changeset: user_changeset)
end
end
答案 1 :(得分:2)
conn = get conn(), "http://example.com/"
答案 2 :(得分:0)
我也遇到了这个问题。虽然似乎没有一种真正惯用的解决问题的方法,但我认为我解决它的方式相当干净。注意:这假设您只使用子域主机。
首先,使用scope =&gt;更新您的配置主机映射,以便您的代码保持干燥状态:
# config.exs
config :my_app, :scope_hosts,
public: "www.",
member_dashboard: "dashboard.",
admin: "admin.",
api: "api."
创建RouterHelpers
模块并将其添加到router.ex
:
# web/router.ex
import MyApp.RouterHelpers
scope host: get_scope_host(:admin), alias: MyApp, as: :admin do
pipe_through [:browser, :admin_layout]
get "/", Admin.PageController, :index
end
scope host: get_scope_host(:member_dashboard), alias: MyApp,
as: :member_dashboard do
pipe_through [:browser, :member_dashboard_layout]
get "/", MemberDashboard.PageController, :index
end
# web/helpers/router_helpers.ex
defmodule MyApp.RouterHelpers do
def get_scope_host(scope) when is_atom(scope) do
Application.get_env(:my_app, :scope_hosts)[scope]
end
end
向TestHelpers
模块添加一个测试助手,该助手将生成一个具有正确范围的完整URL:
# test/support/test_helpers.ex
def host_scoped_path(path, scope) do
host = MyApp.RouterHelpers.get_scope_host(scope)
"http://#{host}myapp.test#{path}"
end
最后,在控制器测试中使用此测试助手:
# test/controllers/member_dashboard/page_controller_test.exs
test "shows member dashboard index page", %{conn: conn} do
conn = get conn, action_url(conn, :index)
assert html_response(conn, 200)=~ "member_dashboard"
end
defp action_url(conn, action) do
member_dashboard_page_path(conn, action)
|> host_scoped_path(:member_dashboard)
end