How to test many_to_many association?

I have two module, book and word, and following are the schema.

schema "books" do
  field :name, :string
  many_to_many :words, Hello.Contents.Word, join_through: "books_words", on_delete: :delete_all

  timestamps()
end

schema "words" do
  field :name, :string
  many_to_many :books, Hello.Contents.Book, join_through: "books_words", on_delete: :delete_all

  timestamps()
end

I write a test case.

test "many_to_many :words" do
   book = book_fixture()
   word = word_fixture()

   book = Repo.preload(book, [:words])
   book_changeset = Ecto.Changeset.change(book)

   book_words_changeset = book_changeset |> Ecto.Changeset.put_assoc(:words, [word])
   Repo.update!(book_words_changeset)

   assert book.words == [word]
end

The test case result.

What is the right way to test many_to_many association?

Change this line:

Repo.update!(book_words_changeset)

to:

book = Repo.update!(book_words_changeset)
1 Like

It works, many thanks for your reply.

1 Like

There are no mutable variables in Elixir. Functions return new values and you must assign those, otherwise you’re losing state – just as it happened with you.

3 Likes

Thanks for the explanation.

No problem. To illustrate this, you can try the following inside iex:

x = %{a: 1, b: 2}
Map.put(x, :c, 3)
IO.inspect(x)

It will still only contain the keys :a and :b.

But if you do this instead:

x = Map.put(x, :c, 3)

Then you’ll see x having all three keys: :a, :b and :c.

1 Like

Thanks for the explanation