halostatue
Ecto: Unit Test for Validating Association Declarations
I’m sharing this because it may be of general interest. I was doing some refactoring of code and removed some automatic aliases when doing use MyApp.Schema, which broke some of my unit tests…but not all of them (I don’t have 100% coverage; imagine that).
The error raised was UndefinedFunctionError for __schema__. After some thinking, this is the unit test I came up with to verify this. The only thing to maintain in it is the list of @relations, which are the application Ecto schemas that have belongs_to, has_many, or many_to_many relationships listed in them.
This will ensure that the relationships are not referring to the wrong aliased module, since Ecto does not (cannot?) verify the module specifications a compile-time. Example:
defmodule MyApp.Business do
use MyApp.Schema
schema "businesses" do
has_many :users, User
end
end
The error is fairly visible, but unless you have a test that exercises the association (via join(Business, :left, [b], assoc(b, :user)), there will be nothing that exposes the missing alias MyApp.User from the module during compilation.
Adding a test like this will help:
defmodule MyApp.ValidEctoRelationsTest do
@moduledoc """
Test that belongs_to, has_many, and many_to_many relationships are valid,
since these things cannot be determined at compile time.
"""
use ExUnit.Case
alias MyApp.Repo
import Ecto.Query
setup do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
end
@relations [
MyApp.Business,
MyApp.User
]
for schema <- @relations, association <- schema.__schema__(:associations) do
test "#{inspect(schema)} has a valid association for #{inspect(association)}" do
assert_valid_relationship(unquote(schema), unquote(association))
end
end
defp assert_valid_relationship(schema, association) do
schema
|> join(:left, [s], assoc(s, ^association))
|> where(false)
|> Repo.all()
assert true
rescue
UndefinedFunctionError ->
%{queryable: module} = schema.__schema__(:association, association)
flunk("""
Schema #{inspect(schema)} association #{inspect(association)} is invalid.
The associated module #{inspect(module)} does not appear to be an Ecto
schema. Is #{inspect(schema)} missing an alias?
""")
end
end
Popular in Discussions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #javascript
- #podcasts
- #code-sync
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








