Ecto Sandbox 对现有进程使用检出连接
Ecto Sandbox use checked out connection for existing process
我有一个带有产品架构的 Phoenix Test 应用程序。
我有一个由主应用程序主管启动的 GenServer,它获取带有 handle_call.
的产品列表
def handle_call(:get_products, _from, _state)
products = Repo.all(Product)
{:reply, products, products}
end
现在我想为这个GenServer写一个测试。
我试过在测试中做这样的事情
setup do
pid = Process.whereis(MyGenServer)
Ecto.Adapters.SQL.Sandbox.allow(Repo, self(), pid)
ProductFactory.insert_list(3, :product) # using ExMachina for factories
end
创建了 3 个产品,我可以在 Repo.all(Product) 的测试中找到它们,但是 运行 宁 MyGenServer.get_products()
将 return 一个空数组.
我没有收到任何错误,只是return一个空数组,好像不存在任何产品。
有什么方法可以让现有的 PID 使用结帐沙箱连接,并在 GenServer 进程中检索我的产品?
PS。我通过在测试设置中重新启动 GenServer 进程设法 运行 测试,但我想知道是否有更多 "elegant" 方法来解决问题。
setup do
Supervisor.terminate_child(MyApp.Supervisor, MyGenServer)
Supervisor.restart_child(MyApp.Supervisor, MyGenServer)
ProductFactory.insert_list(3, :product)
end
谢谢
这是一个最小的 phoenix 应用程序,它与在应用程序主管中启动的 GenServer
一起工作,使用 :shared
模式进行数据库交互。
应用模块:
defmodule TestGenServers.Application do
use Application
def start(_type, _args) do
import Supervisor.Spec
children = [
supervisor(TestGenServers.Repo, []),
supervisor(TestGenServers.Web.Endpoint, []),
worker(TestGenServers.MyServer, [])
]
opts = [strategy: :one_for_one, name: TestGenServers.Supervisor]
Supervisor.start_link(children, opts)
end
end
产品模块:
defmodule TestGenServers.Model.Product do
use Ecto.Schema
import Ecto.Changeset
alias TestGenServers.Model.Product
schema "model_products" do
field :name, :string
timestamps()
end
@doc false
def changeset(%Product{} = product, attrs) do
product
|> cast(attrs, [:name])
|> validate_required([:name])
end
end
GenServer 模块:
defmodule TestGenServers.MyServer do
use GenServer
alias TestGenServers.Repo
def start_link() do
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
end
def handle_call({:get_product, id}, _caller, state) do
{:reply, TestGenServers.Repo.get(TestGenServers.Model.Product, id), state}
end
end
测试模块:
defmodule TestGenServers.TestMyServer do
use TestGenServers.DataCase
setup do
product = Repo.insert!(%TestGenServers.Model.Product{name: "widget123"})
%{product_id: product.id}
end
test "talk to gen server", %{product_id: id} do
assert %{id: ^id, name: "widget123"} = GenServer.call(TestGenServers.MyServer, {:get_product, id})
end
end
DataCase 模块
defmodule TestGenServers.DataCase do
use ExUnit.CaseTemplate
using do
quote do
alias TestGenServers.Repo
import TestGenServers.DataCase
end
end
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(TestGenServers.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(TestGenServers.Repo, {:shared, self()})
end
:ok
end
end
test_helper:
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(TestGenServers.Repo, :manual)
我有一个带有产品架构的 Phoenix Test 应用程序。 我有一个由主应用程序主管启动的 GenServer,它获取带有 handle_call.
的产品列表def handle_call(:get_products, _from, _state)
products = Repo.all(Product)
{:reply, products, products}
end
现在我想为这个GenServer写一个测试。
我试过在测试中做这样的事情
setup do
pid = Process.whereis(MyGenServer)
Ecto.Adapters.SQL.Sandbox.allow(Repo, self(), pid)
ProductFactory.insert_list(3, :product) # using ExMachina for factories
end
创建了 3 个产品,我可以在 Repo.all(Product) 的测试中找到它们,但是 运行 宁 MyGenServer.get_products()
将 return 一个空数组.
我没有收到任何错误,只是return一个空数组,好像不存在任何产品。
有什么方法可以让现有的 PID 使用结帐沙箱连接,并在 GenServer 进程中检索我的产品?
PS。我通过在测试设置中重新启动 GenServer 进程设法 运行 测试,但我想知道是否有更多 "elegant" 方法来解决问题。
setup do
Supervisor.terminate_child(MyApp.Supervisor, MyGenServer)
Supervisor.restart_child(MyApp.Supervisor, MyGenServer)
ProductFactory.insert_list(3, :product)
end
谢谢
这是一个最小的 phoenix 应用程序,它与在应用程序主管中启动的 GenServer
一起工作,使用 :shared
模式进行数据库交互。
应用模块:
defmodule TestGenServers.Application do
use Application
def start(_type, _args) do
import Supervisor.Spec
children = [
supervisor(TestGenServers.Repo, []),
supervisor(TestGenServers.Web.Endpoint, []),
worker(TestGenServers.MyServer, [])
]
opts = [strategy: :one_for_one, name: TestGenServers.Supervisor]
Supervisor.start_link(children, opts)
end
end
产品模块:
defmodule TestGenServers.Model.Product do
use Ecto.Schema
import Ecto.Changeset
alias TestGenServers.Model.Product
schema "model_products" do
field :name, :string
timestamps()
end
@doc false
def changeset(%Product{} = product, attrs) do
product
|> cast(attrs, [:name])
|> validate_required([:name])
end
end
GenServer 模块:
defmodule TestGenServers.MyServer do
use GenServer
alias TestGenServers.Repo
def start_link() do
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
end
def handle_call({:get_product, id}, _caller, state) do
{:reply, TestGenServers.Repo.get(TestGenServers.Model.Product, id), state}
end
end
测试模块:
defmodule TestGenServers.TestMyServer do
use TestGenServers.DataCase
setup do
product = Repo.insert!(%TestGenServers.Model.Product{name: "widget123"})
%{product_id: product.id}
end
test "talk to gen server", %{product_id: id} do
assert %{id: ^id, name: "widget123"} = GenServer.call(TestGenServers.MyServer, {:get_product, id})
end
end
DataCase 模块
defmodule TestGenServers.DataCase do
use ExUnit.CaseTemplate
using do
quote do
alias TestGenServers.Repo
import TestGenServers.DataCase
end
end
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(TestGenServers.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(TestGenServers.Repo, {:shared, self()})
end
:ok
end
end
test_helper:
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(TestGenServers.Repo, :manual)