Skip to main content
ClaudeWave
Skill440 estrellas del repoactualizado yesterday

testing

This skill provides Elixir testing patterns and best practices for ExUnit, Mox mocking, factory setup, and LiveView testing. Use it when writing or debugging test files (ending in _test.exs), creating factory definitions, configuring test support modules, or troubleshooting test failures in Phoenix and Elixir applications.

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/oliver-kriska/claude-elixir-phoenix /tmp/testing && cp -r /tmp/testing/plugins/elixir-phoenix/skills/testing ~/.claude/skills/testing
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# Elixir Testing Reference

> **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?

| Testing | Use |
|---------|-----|
| Controller/API | `use MyAppWeb.ConnCase` |
| Context/Schema | `use MyApp.DataCase` |
| LiveView | `use MyAppWeb.ConnCase` + `import Phoenix.LiveViewTest` |
| Pure logic | `use 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

```elixir
# 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

| Wrong | Right |
|-------|-------|
| `Process.sleep(100)` | `assert_receive {:done, _}, 5000` |
| `insert(:user)` in factory | `build(:user)` in factory |
| `async: true` with `set_mox_global()` | `async: false` |
| Mock internal modules | Test through public API |

## References

For detailed patterns, see:

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