Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test models with required associations

Using 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

My test fails with

** (RuntimeError) casting assocs with cast/3 is not supported, use cast_assoc/3 instead

Looking at the documentation is says that cast_assoc/3 needs to be called after cast/3 so I'm pretty sure I'm missing something essential to get this test to work.

Edit: Updated my code and now receiving a new error:

** (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}

I'm guessing my @valid_attrs are malformed some how?

like image 900
Alejandro Huerta Avatar asked Jun 22 '16 05:06

Alejandro Huerta


People also ask

How do I run a Rails test?

2.7 The Rails Test Runner Or we can run a single test file by passing the bin/rails test command the filename containing the test cases. This will run all test methods from the test case. You can also run a particular test method from the test case by providing the -n or --name flag and the test's method name.

Is RSpec used for unit testing?

RSpec is a unit test framework for the Ruby programming language. RSpec is different than traditional xUnit frameworks like JUnit because RSpec is a Behavior driven development tool. What this means is that, tests written in RSpec focus on the "behavior" of an application being tested.


1 Answers

  1. You don't need to pass the names of associations to cast or validate_required. You should remove it from @required_fields. cast_assoc will handle converting those fields to structs and, if you pass required: true, will validate that they're present. (For those who didn't read the comments above, see revision 1 of the question for the context.)

  2. @valid_attrs should be a normal map, like you would get as params in a Phoenix Controller's functions. cast_assoc will handle converting a raw map into a struct. So, change

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

    to

    @valid_attrs %{board_pieces: [%{x: 0, y: 0}], empire: %{}}
    
like image 167
Dogbert Avatar answered Sep 17 '22 06:09

Dogbert