Elixir:当Phoenix控制器需要数据库中的记录时,如何测试它们?用种子还是模仿?

Elixir:当Phoenix控制器需要数据库中的记录时,如何测试它们?用种子还是模仿?,elixir,phoenix-framework,Elixir,Phoenix Framework,在测试控制器时,在测试数据库中有一些数据可能很有用。有时您可能需要测试数据创建。正确的设置方法是什么?控制器测试应测试控制器的创建功能是否工作,而不是模型 作为一个例子,我想测试一个会话控制器,我有两个测试。一个是测试创建的用户是否可以登录。另一个是,如果密码错误,他就不能。两者都依赖于数据库中的用户。我现在的处理方法是首先创建用户: defmodule MyApp.SessionControllerTest do use MyApp.ConnCase alias MyApp.Admi

在测试控制器时,在测试数据库中有一些数据可能很有用。有时您可能需要测试数据创建。正确的设置方法是什么?控制器测试应测试控制器的
创建
功能是否工作,而不是模型

作为一个例子,我想测试一个会话控制器,我有两个测试。一个是测试创建的用户是否可以登录。另一个是,如果密码错误,他就不能。两者都依赖于数据库中的用户。我现在的处理方法是首先创建用户:

defmodule MyApp.SessionControllerTest do
  use MyApp.ConnCase

  alias MyApp.Admin
  @valid_attrs %{email: "email@example.com", name: "John Doe", password: "goodpassword", password_confirmation: "goodpassword", password_hash: "somecontent", username: "username"}
  @invalid_attrs %{}

  setup do
    {:ok, conn: put_req_header(conn, "accept", "application/json")}
  end

  test "admin can login after creation" do
    conn = post conn, admin_path(conn, :create), admin: @valid_attrs
    body = json_response(conn, 201)
    assert Repo.get_by(Admin, email: @valid_attrs[:email])
    conn = post conn, session_path(conn, :create), %{data: %{attributes: %{email: @valid_attrs[:email], password: @valid_attrs[:password]}}}
    body = json_response(conn, 201)
    assert body["data"]["token"]
  end

  test "login with wrong password returns an error" do
    conn = post conn, session_path(conn, :create), %{data: %{attributes: %{email: @valid_attrs[:email], password: "wrongpassword"}}}
    body = json_response(conn, 403)
    assert body["error"]
  end

end
如果我现在在我的
Admin
模型上添加一个唯一性约束,这可能会变得混乱,因为每当我需要数据库中的用户时,我必须确保测试不会因为该约束而失败,而是因为被测控制器中的某个错误。此外,还不清楚测试的运行顺序,在几个测试中保持数据创建的一致性似乎是一场噩梦

我想要一个在开始时定义创建数据的位置。或者使用模拟进行控制器测试


这怎么可能呢?

使用
设置功能向数据库添加一些数据

setup do
  Repo.insert!(%User{id: 1, password: "somepassword", ....})
  ....
  :ok
end
每次测试前都会调用
设置
。 有关更多信息,请参阅

要在同步模式下逐步运行测试,请添加
async:false
以使用调用

defmodule MyApp.SessionControllerTest do
  use MyApp.ConnCase, async: false`
但我认为运行测试时最好不要依赖于其他测试

defmodule MyApp.SessionControllerTest do
  use MyApp.ConnCase

  alias MyApp.Admin
  @valid_attrs %{email: "email@example.com", name: "John Doe", password: "goodpassword", password_confirmation: "goodpassword", password_hash: "somecontent", username: "username"}
  @invalid_attrs %{}

  setup do
    Repo.insert!(%User{email: "bar@example.com", password: "somepassword", ....})
    {:ok, conn: put_req_header(conn, "accept", "application/json")}
  end

  ...

  test "login with wrong password returns an error" do
    conn = post conn, session_path(conn, :create), %{data: %{attributes: %{email: "bar@example.com", password: "wrongpassword"}}}
    body = json_response(conn, 403)
    assert body["error"]
  end

end

希望有帮助。

晚会有点晚了,但它可能会帮助其他人

我建议使用ex_machina工厂库。 使用它,您可以在一个地方定义和创建测试数据

这样定义工厂:

defmodule MyApp.Factory do
  # with Ecto
  use ExMachina.Ecto, repo: MyApp.Repo

  # without Ecto
  use ExMachina

  def user_factory do
    %MyApp.User{
      name: "Jane Smith",
      email: sequence(:email, &"email-#{&1}@example.com"),
    }
  end

  def article_factory do
    %MyApp.Article{
      title: "Use ExMachina!",
      # associations are inserted when you call `insert`
      author: build(:user),
    }
  end

  def comment_factory do
    %MyApp.Comment{
      text: "It's great!",
      article: build(:article),
    }
  end
end
创建一个记录将是:

insert(:comment, article: article)
还可以生成记录(未保存)


因为他的部分问题是关于测试之间的隔离,所以可能值得注意的是,Ecto 2(目前处于测试阶段)允许在沙箱环境中进行并发数据库测试。@CodyPoll:这是一个非常好的提示,而这个链接可能会回答这个问题,最好在这里包括答案的基本部分,并提供链接供参考。如果链接页面发生更改,仅链接的答案可能无效。-改变了我的答案,希望这更好。
build(:user)