elixir-testing
Elixir testing patterns: ExUnit, Mox behaviour-based mocking, StreamData property testing, Phoenix integration tests. Use when writing tests for Elixir/Phoenix applications.
Best use case
elixir-testing is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Elixir testing patterns: ExUnit, Mox behaviour-based mocking, StreamData property testing, Phoenix integration tests. Use when writing tests for Elixir/Phoenix applications.
Teams using elixir-testing should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/elixir-testing/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How elixir-testing Compares
| Feature / Agent | elixir-testing | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Elixir testing patterns: ExUnit, Mox behaviour-based mocking, StreamData property testing, Phoenix integration tests. Use when writing tests for Elixir/Phoenix applications.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Elixir Testing Patterns
Comprehensive testing strategies for Elixir and Phoenix applications.
## When to Use
- Writing unit, integration, or property-based tests for Elixir code
- Setting up behaviour-based mocking with Mox
- Testing Phoenix controllers, LiveViews, and channels
- Designing test factories and fixtures
## ExUnit Fundamentals
```elixir
defmodule MyApp.AccountsTest do
use MyApp.DataCase, async: true # async for concurrent test execution
alias MyApp.Accounts
describe "create_user/1" do
test "with valid attrs creates a user" do
attrs = %{email: "test@example.com", name: "Test", password: "password123"}
assert {:ok, user} = Accounts.create_user(attrs)
assert user.email == "test@example.com"
end
test "with invalid email returns error changeset" do
assert {:error, changeset} = Accounts.create_user(%{email: "bad"})
assert %{email: ["has invalid format"]} = errors_on(changeset)
end
end
end
```
### Key Practices
| Practice | Details |
|----------|---------|
| `async: true` | Use when tests don't share global state (most unit tests) |
| `describe` blocks | Group related tests logically |
| `@tag :slow` | Tag slow/integration tests for filtering: `mix test --exclude slow` |
| `setup` | Runs before each test; return map merged into test context |
| `setup_all` | Runs once per module |
| Doctests | `doctest MyModule` to verify documentation examples |
## Mox (Behaviour-Based Mocking)
Only mock at integration boundaries — never mock internal modules.
### 1. Define a behaviour
```elixir
defmodule MyApp.HTTPClient do
@callback get(String.t()) :: {:ok, map()} | {:error, term()}
end
```
### 2. Create mock in test_helper.exs
```elixir
Mox.defmock(MyApp.MockHTTPClient, for: MyApp.HTTPClient)
```
### 3. Use in tests
```elixir
defmodule MyApp.WeatherTest do
use ExUnit.Case, async: true
import Mox
setup :verify_on_exit!
test "fetches weather for city" do
expect(MyApp.MockHTTPClient, :get, fn url ->
assert url =~ "london"
{:ok, %{"temp" => 15, "condition" => "cloudy"}}
end)
assert {:ok, weather} = MyApp.Weather.fetch("london")
assert weather.temp == 15
end
end
```
### 4. Configure in config/test.exs
```elixir
config :my_app, :http_client, MyApp.MockHTTPClient
```
## Property-Based Testing (StreamData)
Test invariants across random inputs instead of specific cases:
```elixir
defmodule MyApp.SortTest do
use ExUnit.Case, async: true
use ExUnitProperties
property "sorting is idempotent" do
check all list <- list_of(integer()) do
sorted = Enum.sort(list)
assert Enum.sort(sorted) == sorted
end
end
property "sorted list preserves length" do
check all list <- list_of(integer()) do
assert length(Enum.sort(list)) == length(list)
end
end
property "email validation accepts valid emails" do
check all name <- string(:alphanumeric, min_length: 1),
domain <- string(:alphanumeric, min_length: 1) do
email = "#{name}@#{domain}.com"
changeset = User.registration_changeset(%User{}, %{email: email, name: "T", password: "password1"})
assert changeset.valid? || Keyword.has_key?(changeset.errors, :email)
end
end
end
```
## Phoenix LiveView Testing
```elixir
defmodule MyAppWeb.UserLiveTest do
use MyAppWeb.ConnCase, async: true
import Phoenix.LiveViewTest
test "renders user list", %{conn: conn} do
user = insert(:user, name: "Alice")
{:ok, view, html} = live(conn, ~p"/users")
assert html =~ "Alice"
end
test "creates user via form", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/users/new")
view
|> form("#user-form", user: %{name: "Bob", email: "bob@test.com"})
|> render_submit()
assert_redirect(view, ~p"/users")
end
test "live updates on PubSub broadcast", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/dashboard")
Phoenix.PubSub.broadcast(MyApp.PubSub, "stats", {:update, %{count: 42}})
assert render(view) =~ "42"
end
end
```
## Phoenix Controller Testing
```elixir
defmodule MyAppWeb.UserControllerTest do
use MyAppWeb.ConnCase, async: true
describe "GET /api/users" do
test "returns list of users", %{conn: conn} do
insert(:user, name: "Alice")
conn = get(conn, ~p"/api/users")
assert [%{"name" => "Alice"}] = json_response(conn, 200)["data"]
end
end
end
```
## Test Factories (ExMachina)
```elixir
defmodule MyApp.Factory do
use ExMachina.Ecto, repo: MyApp.Repo
def user_factory do
%MyApp.Accounts.User{
email: sequence(:email, &"user#{&1}@example.com"),
name: sequence(:name, &"User #{&1}"),
password_hash: Bcrypt.hash_pwd_salt("password123")
}
end
def post_factory do
%MyApp.Blog.Post{
title: sequence(:title, &"Post #{&1}"),
body: "Content",
author: build(:user)
}
end
end
```
## External HTTP Mocking (Bypass)
```elixir
test "handles API timeout" do
bypass = Bypass.open()
Bypass.expect(bypass, fn conn ->
Process.sleep(5_000) # Simulate timeout
Plug.Conn.send_resp(conn, 200, "")
end)
assert {:error, :timeout} = MyApp.API.fetch("http://localhost:#{bypass.port}/data")
end
```
## Anti-Patterns
- **Mocking internal modules**: Only mock at boundaries (HTTP, email, external APIs)
- **Ad-hoc mocks without behaviours**: Mox enforces contracts; ad-hoc mocks drift
- **Not using async**: Most tests can run concurrently — default to `async: true`
- **Testing implementation details**: Test behavior and outcomes, not internal calls
- **Slow tests without tags**: Tag with `@tag :slow` so devs can exclude them
## Key Libraries
- `ExUnit` (stdlib), `Mox`, `StreamData` (property testing)
- `ExMachina` (factories), `Faker` (fake data)
- `Bypass` (HTTP mock server), `Wallaby` (browser testing)
- `Hammox` (Mox + typespec checking)Related Skills
wordpress-penetration-testing
This skill should be used when the user asks to "pentest WordPress sites", "scan WordPress for vulnerabilities", "enumerate WordPress users, themes, or plugins", "exploit WordPress vu...
elixir-pro
Write idiomatic Elixir code with OTP patterns, supervision trees, and Phoenix LiveView. Masters concurrency, fault tolerance, and distributed systems.
elixir-otp-patterns
OTP architecture patterns for Elixir: GenServer, Supervisor, DynamicSupervisor, Registry, Application. Use when designing fault-tolerant process architectures, supervision trees, or stateful services.
elixir-deployment
Elixir deployment patterns: Mix releases, Docker multi-stage builds, clustering with libcluster, runtime config, health checks, observability. Use when deploying Elixir/Phoenix to production.
elixir-concurrency
Elixir concurrency patterns: Tasks, GenStage pipelines, Broadway data ingestion, Flow parallel processing, Oban background jobs. Use when building concurrent or parallel data processing systems.
web-security-testing
Web application security testing workflow for OWASP Top 10 vulnerabilities including injection, XSS, authentication flaws, and access control issues.
ssh-penetration-testing
This skill should be used when the user asks to "pentest SSH services", "enumerate SSH configurations", "brute force SSH credentials", "exploit SSH vulnerabilities", "perform SSH tu...
sqlmap-database-pentesting
This skill should be used when the user asks to "automate SQL injection testing," "enumerate database structure," "extract database credentials using sqlmap," "dump tables and columns...
sql-injection-testing
This skill should be used when the user asks to "test for SQL injection vulnerabilities", "perform SQLi attacks", "bypass authentication using SQL injection", "extract database inform...
smtp-penetration-testing
This skill should be used when the user asks to "perform SMTP penetration testing", "enumerate email users", "test for open mail relays", "grab SMTP banners", "brute force email cre...
idor-testing
This skill should be used when the user asks to "test for insecure direct object references," "find IDOR vulnerabilities," "exploit broken access control," "enumerate user IDs or obje...
html-injection-testing
This skill should be used when the user asks to "test for HTML injection", "inject HTML into web pages", "perform HTML injection attacks", "deface web applications", or "test conten...