【问题标题】:Best practice for testing Elixir Ecto model associations测试 Elixir Ecto 模型关联的最佳实践
【发布时间】:2015-11-26 00:33:52
【问题描述】:

我正在尝试测试 Elixir 中的归属关联。

假设我有两个模型,一个 Product 和一个 ProductType。产品属于一种产品类型。

defmodule Store.Product do
  use Store.Web, :model

  schema "products" do
    field :name, :string

    belongs_to :type, Store.ProductType, foreign_key: :product_type_id

    timestamps
  end

  @required_fields ~w(name product_type_id)

  @optional_fields ~w()

  def changeset(model, params \\ :empty) do
    model
    |> cast(params, @required_fields, @optional_fields)
  end
end

defmodule Store.ProductType do
  use Store.Web, :model

  schema "product_types" do
    field :name, :string

    timestamps
  end

  @required_fields ~w(name)
  @optional_fields ~w()

  def changeset(model, params \\ :empty) do
    model
    |> cast(params, @required_fields, @optional_fields)
  end
end

这是我的测试文件中的内容:

defmodule Store.ProductTest do
  use Store.ModelCase

  alias Store.Repo
  alias Store.Product
  alias Store.ProductType

  @valid_attrs %{
    name: "pickles", 
    product_type_id: 42,
  }

  @invalid_attrs %{}

  test "product type relationship" do
    product_type_changeset = ProductType.changeset(
      %ProductType{}, %{name: "Foo"}
    )
    product_type = Repo.insert!(product_type_changeset)

    product_changeset = Product.changeset(
      %Product{}, %{@valid_attrs | product_type_id: product_type.id}
    )
    product = Repo.insert!(product_changeset)

    product = Product |> Repo.get(product.id) |> Repo.preload(:type)
    assert product_type == product.type
  end
end

我基本上是在创建产品类型,创建产品,从数据库中获取产品记录并验证类型与我创建的类型相同。

这是一个合理的方法吗?

编辑

为了子孙后代,这是一个不使用变更集的更简洁的测试:

test "belongs to product type" do
  product_type = Repo.insert!(%ProductType{})
  product = Repo.insert!(%Product{product_type_id: product_type.id})
  product = Product |> Repo.get(product.id) |> Repo.preload(:type)
  assert product_type == product.type
end

要测试这种关联,您基本上可以放弃强制转换和验证。

【问题讨论】:

    标签: elixir phoenix-framework ecto


    【解决方案1】:

    我根本不会明确测试这个 - 你基本上是在这里测试 Ecto。

    这种事情我通常会隐式测试,例如控制器测试,您可以在其中发布一些内容,然后确保在数据库中创建了正确的数据。

    如果您想对此进行单元测试,您需要考虑您到底想要比较什么。测试插入的产品类型的 id 是否与插入的产品的 product_type_id 相同就足够了,但这感觉很奇怪,因为这样更明显的是你只是在这里测试 ecto 功能。

    【讨论】:

    • 我明白你在说什么,但我不确定我是否同意这一点。测试模型中的关联不仅仅是测试 Ecto,它是一个单元测试,用于验证我的系统是否按照我期望的方式运行。我希望我的产品模型具有产品类型关联。我的测试验证了这种关系是否存在,并且验证了关联名称“type”设置是否正确。控制器测试也可以验证这些东西,但它更像是一个集成测试,我也认为这很有价值。在我的 Rails 应用程序中,我倾向于使用这两种类型的测试。
    • 正如我所说,如果你真的想测试它,你需要确定你正在测试的是什么:为了测试关联是否持续存在,我想说它应该足以比较身份证。所以assert product.product_type_id == product_type.id
    • 我正在测试该关系是否存在并且可以与预期的名称一起使用。仅测试 ids 匹配并不能验证是否存在 belongs_to 关联设置。我可以在我的产品模型上有一个 product_type_id 字段,我可以将其设置为与产品类型记录的 id 相同的值。他们会匹配,但在产品模型上调用关联会失败。仅比较 ID 不会暴露这一点。
    【解决方案2】:

    测试 Ecto 关联的一个很好的参考是 Ecto 用于测试关联的实际测试。你可以在他们的 GitHub 上查看。

    https://github.com/elixir-ecto/ecto/blob/master/test/ecto/schema_test.exs

    这是一个例子:

    test "belongs_to account" do
      association =
        %Ecto.Association.BelongsTo{cardinality: :one, defaults: [],
                                    field: :account, on_cast: nil,
                                    on_replace: :raise, owner: AccountUser,
                                    owner_key: :account_id, queryable: Account,
                                    related: Account, related_key: :id,
                                    relationship: :parent, unique: true}
    
      assert AccountUser.__schema__(:association, :account) == association
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-29
      • 2020-02-05
      • 1970-01-01
      相关资源
      最近更新 更多