Alv*_*aro 0 postgresql unit-testing elixir ecto
我在 Elixir 中有一个非常简单的应用程序,它使用 Ecto 在 Postgres 上的表中运行 SELECT 查询。\n表名称是“person”,有 2 列:“name”和“age”。
\n这是应用程序:
\n/ecto_app\n |-application.ex\n |-repo.ex\n
Run Code Online (Sandbox Code Playgroud)\n应用程序.ex:
\ndefmodule EctoApp.Application do\n\n use Application\n\n require Logger\n\n @impl true\n def start(_type, _args) do\n children = [\n EctoApp.Repo\n ]\n\n opts = [strategy: :one_for_one, name: EctoApp.Supervisor]\n Logger.debug("Starting Ecto App")\n Supervisor.start_link(children, opts)\n end\nend\n
Run Code Online (Sandbox Code Playgroud)\n回购协议:
\ndefmodule EctoApp.Repo do\n use Ecto.Repo,\n otp_app: :ecto_app,\n adapter: Ecto.Adapters.Postgres\n\n import Ecto.Query\n\n require Logger\n\n\n def get_people() do\n query = from p in "person",\n select: [p.name, p.age]\n result= EctoApp.Repo.all(query)\n Logger.debug(result)\n end\n\nend\n
Run Code Online (Sandbox Code Playgroud)\n我正在使用这两个库:
\n[\n {:ecto_sql, "~> 3.0"},\n {:postgrex, ">= 0.0.0"}\n]\n
Run Code Online (Sandbox Code Playgroud)\n该应用程序工作正常,但问题是我想为存储库进行单元测试,但我可以 xc2xb4t 弄清楚如何模拟 Postgres 连接,因为我不想启动 Postgres 实例来运行测试。
\n有谁知道如何 Mock 或我可以使用哪个库来“模拟”与 Postgres 的连接,以便我可以对 repo 类进行测试覆盖?
\n谢谢!
\n您不需要像模拟其他功能一样模拟 PostGres 连接。这是因为 PostGres 可以将操作包装在可撤消事务中。结论是,您的测试使用真实的连接并对真实的数据库发出真实的请求,但该数据库是专用于测试并通过特殊适配器发出查询的数据库。这是迄今为止实现数据库支持的应用程序测试覆盖率的最常见方法;尝试模拟数据库连接会导致脆弱的测试充满误报,因此这种做法并不常见,尤其是当针对真实数据库发出所有请求非常简单时。
以下是在代码中促进这一点的重要部分:
# config/dev.exs
config :my_app, MyApp.Repo,
pool: DBConnection.ConnectionPool,
database: "something_dev",
# ... etc...
# config/test.exs
config :my_app, MyApp.Repo,
pool: Ecto.Adapters.SQL.Sandbox,
database: "something_test",
# ... etc...
Run Code Online (Sandbox Code Playgroud)
Repo
适配器的使用情况。这就是将操作包装在事务中的原因,以便您可以安全地重新运行测试,而无需进行过多的清理。一个好的地方是在setup 回调中,它在模块中的每个测试之前运行:defmodule MyApp.SomeTest do
use ExUnit.Case # you may require async: false
alias Ecto.Adapters.SQL.Sandbox
alias MyApp.Repo
setup do
Sandbox.checkout(Repo)
end
describe "get_people/0" do
test "select" do
# insert fake records here
assert [] = Repo.get_people()
end
end
end
Run Code Online (Sandbox Code Playgroud)
还有一些提示:
正如所写的,您的get_people/0
函数不会返回result
. 请记住,Elixir 依赖于隐式返回,因此它返回最后一个操作的结果。在您的情况下,返回的结果将是调试语句的结果,这只是一个:ok
而不是result
您所期望的。
不要忘记您可能需要对测试数据库运行迁移——这不是自动发生的事情。您可以在测试之前创建一个别名mix.exs
来执行,或者您可以只记得针对测试数据库运行等。mix ecto.migrate
MIX_ENV=test mix ecto.drop
您经常会发现自动构建数据“固定装置”(即正确形状的虚假记录)很有帮助。ex_machina包是执行此操作的一种便捷方法,但无论您使用包还是推出自己的装置,您的测试都需要使用您期望的任何测试记录来准备数据库,作为标准中“安排”步骤的一部分“安排-行动-断言”测试方法。
如果您的情况确实需要模拟数据库连接,那么我会推荐一种依赖于一种“依赖注入”的简单模式,例如您可以将模块重写Repo
为函数参数或从配置中提取的内容,例如
def get_people(repo \\ Repo)
query = from p in "person",
select: [p.name, p.age]
repo.all(query)
end
Run Code Online (Sandbox Code Playgroud)