如何测试具有所需关联的模型

时间:2016-06-22 05:52:00

标签: elixir ecto ex-unit

使用Ecto 2.0:

defmodule PlexServer.BoardInstanceTest do
  use PlexServer.ModelCase

  alias PlexServer.BoardInstance

  @valid_attrs %{board_pieces: [%PlexServer.BoardTileInstance{x: 0, y: 0}], empire: %PlexServer.EmpireInstance{}}
  @invalid_attrs %{}

  test "changeset with valid attributes" do
    changeset = BoardInstance.changeset(%BoardInstance{}, @valid_attrs)
    assert changeset.valid?
  end
end

defmodule PlexServer.BoardInstance do
  use PlexServer.Web, :model

  alias PlexServer.BoardTileInstance

  schema "board_instances" do  
    belongs_to :empire, PlexServer.EmpireInstance
    has_many :board_pieces, BoardTileInstance

    timestamps
  end

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

  def changeset(model, params \\ :empty) do
    model
      |> cast(params, @required_fields, @optional_fields)
      |> cast_assoc(:board_pieces, required: true)
      |> cast_assoc(:empire, require: true)
  end
end

我的测试失败了

  

**(RuntimeError)不支持使用cast / 3转换关联,而是使用cast_assoc / 3

查看文档说,cast /assoc / 3需要在cast / 3之后调用,所以我很确定我错过了让这个测试起作用所必需的东西。

编辑:更新了我的代码,现在收到一个新错误:

  

**(Ecto.CastError)预期params为地图,得到:%PlexServer.BoardTileInstance{__meta__: #Ecto.Schema.Metadata<:built>, fleets: #Ecto.Association.NotLoaded<association :fleets is not loaded>, id: nil, inserted_at: nil, system: #Ecto.Association.NotLoaded<association :system is not loaded>, updated_at: nil, x: 0, y: 0}

我猜测我的@valid_attrs有多么糟糕?

1 个答案:

答案 0 :(得分:6)

  1. 您无需将关联名称传递给castvalidate_required。您应该从@required_fields中删除它。 cast_assoc将处理将这些字段转换为结构,如果您通过required: true,则会验证它们是否存在。 (对于那些没有阅读上述评论的人,请参阅revision 1 of the question了解相关情况。)

  2. @valid_attrs应该是一张法线贴图,就像你在Phoenix Controller的函数中得到params一样。 cast_assoc将处理将原始地图转换为结构。所以,改变

    @valid_attrs %{board_pieces: [%PlexServer.BoardTileInstance{x: 0, y: 0}], empire: %PlexServer.EmpireInstance{}}
    

    @valid_attrs %{board_pieces: [%{x: 0, y: 0}], empire: %{}}