如何测试具有所需关联的模型
How to test models with required associations
使用 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) casting assocs with cast/3 is not supported, use cast_assoc/3 instead
查看文档说 cast_assoc/3 需要在 cast/3 之后调用,所以我很确定我遗漏了使此测试正常工作所必需的东西。
编辑:更新了我的代码,现在收到一个新错误:
** (Ecto.CastError) expected params to be a map, got: %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 格式有问题怎么办?
您不需要将协会名称传递给 cast
或 validate_required
。您应该将其从 @required_fields
中删除。 cast_assoc
将处理将这些字段转换为结构,如果您传递 required: true
,将验证它们是否存在。 (对于那些没有阅读上面评论的人,请参阅revision 1 of the question了解上下文。)
@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: %{}}
使用 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) casting assocs with cast/3 is not supported, use cast_assoc/3 instead
查看文档说 cast_assoc/3 需要在 cast/3 之后调用,所以我很确定我遗漏了使此测试正常工作所必需的东西。
编辑:更新了我的代码,现在收到一个新错误:
** (Ecto.CastError) expected params to be a map, got:
%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 格式有问题怎么办?
您不需要将协会名称传递给
cast
或validate_required
。您应该将其从@required_fields
中删除。cast_assoc
将处理将这些字段转换为结构,如果您传递required: true
,将验证它们是否存在。 (对于那些没有阅读上面评论的人,请参阅revision 1 of the question了解上下文。)@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: %{}}