Elixir Testing Reference

SkillAI & models

Write or repair Elixir tests with ExUnit, sandbox isolation, async reliability,

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Elixir Testing Reference skill

What this skill tells your AI

The instructions your AI receives, as published by oliver-kriska/claude-elixir-phoenix in targets/pi/skills/testing/SKILL.md and read by ahel’s review.

Ash projects: Use DataCase with Ash.Test helpers; test actions via domain code interfaces, not direct Repo calls. See ash-framework skill.

Quick reference for Elixir testing patterns.

Iron Laws — Never Violate These

  1. ASYNC BY DEFAULT — Use async: true unless tests modify global state
  2. SANDBOX ISOLATION — All database tests use Ecto.Adapters.SQL.Sandbox
  3. MOCK ONLY AT BOUNDARIES — Never mock database, internal modules, or stdlib
  4. BEHAVIOURS AS CONTRACTS — All mocks must implement a defined @callback behaviour
  5. BUILD BY DEFAULT — Use build/2 in factories; insert/2 only when DB needed
  6. NO PROCESS.SLEEP — Use assert_receive with timeout for async operations
  7. VERIFY_ON_EXIT! — Always call in Mox tests setup
  8. FACTORIES MATCH SCHEMA REQUIRED FIELDS — Factory definitions must include all fields that have validate_required in the schema changeset. Missing fields cause cascading test failures

Quick Decisions

Which Test Case?

TestingUse
Controller/APIuse MyAppWeb.ConnCase
Context/Schemause MyApp.DataCase
LiveViewuse MyAppWeb.ConnCase + import Phoenix.LiveViewTest
Pure logicuse ExUnit.Case, async: true

When to use async: true?

  • ✅ Pure functions, no shared state
  • ✅ Database tests with Sandbox (PostgreSQL)
  • ❌ Tests modifying Application.put_env
  • ❌ Tests using Mox global mode

Mock or not?

  • ✅ Mock: External APIs, email services, file storage
  • ❌ Don't mock: Database, internal modules, stdlib

build() or insert()?

  • Use build() by default for speed
  • Use insert() only when you need DB ID, constraints, or persisted associations

Quick Patterns

# Setup chain
setup [:create_user, :authenticate]

# Pattern matching assertion
assert {:ok, %User{name: name}} = create_user(attrs)

# Async message assertion
assert_receive {:user_created, _}, 5000

# Mox setup
setup :verify_on_exit!
expect(MockAPI, :call, fn _ -> {:ok, "data"} end)

# LiveView async
html = render_async(view)  # MUST call for assign_async

Common Anti-patterns

WrongRight
Process.sleep(100)assert_receive {:done, _}, 5000
insert(:user) in factorybuild(:user) in factory
async: true with set_mox_global()async: false
Mock internal modulesTest through public API

References

For detailed patterns, see:

  • references/exunit-patterns.md - Setup, assertions, tags
  • references/mox-patterns.md - Behaviours, expect/stub, async
  • references/liveview-testing.md - Forms, async, uploads
  • references/factory-patterns.md - ExMachina, sequences, traits

Signals

GitHub stars
543
Forks
38
Last commit
Sep 2026
Hacker News mentions
20
Advanced
Catalog kind
skill
Gateway key
testing-oliver-kriska
Source
github.com/oliver-kriska/claude-elixir-phoenix