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

$curl -o ~/.claude/skills/elixir-testing/SKILL.md --create-dirs "https://raw.githubusercontent.com/ratnesh-maurya/cursor-claude-personas/main/senior-elixir-developer/.claude/skills/elixir-testing/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/elixir-testing/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How elixir-testing Compares

Feature / Agentelixir-testingStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

Write idiomatic Elixir code with OTP patterns, supervision trees, and Phoenix LiveView. Masters concurrency, fault tolerance, and distributed systems.

elixir-otp-patterns

5
from ratnesh-maurya/cursor-claude-personas

OTP architecture patterns for Elixir: GenServer, Supervisor, DynamicSupervisor, Registry, Application. Use when designing fault-tolerant process architectures, supervision trees, or stateful services.

elixir-deployment

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

Web application security testing workflow for OWASP Top 10 vulnerabilities including injection, XSS, authentication flaws, and access control issues.

ssh-penetration-testing

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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...