3.2 KiB
3.2 KiB
name, description
| name | description |
|---|---|
| test-writer | Writes tests following Elixir/Phoenix best practices. Ensures DRY tests with proper helper functions, no duplicated setup code, and correct parameter defaults. Use when writing or modifying tests. |
Test Writer Skill
Overview
This skill provides guidelines for writing clean, maintainable Elixir/Phoenix tests following best practices. It focuses mainly on integration tests. For unit tests, we also want glanceable tests with unique names for values, test helpers, custom matchers and shared setups where appropriate.
Core Principles
1. DRY Tests
Avoid duplication by creating focused helper functions:
Bad:
test "GET /users returns index", %{conn: conn} do
conn = get(conn, "/users")
body = html_response(conn, 200)
assert body =~ "Users"
end
test "GET /users/:id returns show", %{conn: conn} do
conn = get(conn, "/users/1")
body = html_response(conn, 200)
assert body =~ "User"
end
Good:
defp goto_users_page(conn, suffix \\ ""), do: get(conn, "/users" <> suffix)
test "GET /users returns index", %{conn: conn} do
conn = goto_users_page(conn)
assert html_response(conn, 200) =~ "Users"
end
test "GET /users/:id returns show", %{conn: conn} do
conn = goto_users_page(conn, "/1")
assert html_response(conn, 200) =~ "User"
end
2. Separate Helpers for Different Assertion Patterns
Don't use conditionals in helpers to handle different cases:
Bad:
defp goto_users_page(conn, suffix \\ "", check_title \\ true) do
path = "/users" <> suffix
conn = get(conn, path)
body = html_response(conn, 200)
if check_title, do: assert body =~ "Users"
assert body =~ "AppLayout"
body
end
Good:
defp goto_users_page(conn, suffix \\ "") do
path = "/users" <> suffix
conn = get(conn, path)
body = html_response(conn, 200)
assert body =~ "Users"
assert body =~ "AppLayout"
body
end
defp goto_user_page(conn, suffix) do
path = "/users" <> suffix
conn = get(conn, path)
body = html_response(conn, 200)
assert body =~ "AppLayout"
body
end
Test Structure
Context Block
describe "resource name" do
# Shared setup in context if needed
# test "scenario" do ...
end
Value Aliasing
Never reuse value names. Elixir is immutable, but value aliasing is confusing. Use unique, meaningful names for the left hand side of assignments. Or use pipes |> to eliminate the need for naming.
test "GET /users returns index", %{conn: conn} do
# don't reassign
response = get(conn, "/users")
# ...
end
Common Patterns
HTML Pages with Layout
defp goto_resource_page(conn, suffix \\ ""), do: ...
# Asserts common layout elements and page-specific content
API Endpoints
test "GET /api/resource returns JSON", %{conn: conn} do
conn = conn |> put_req_header("accept", "application/json")
conn = get(conn, "/api/resource")
response = json_response(conn, 200)
# Assert structure
end
Error Handling
test "returns 404 for nonexistent", %{conn: conn} do
assert html_response(get(conn, "/nonexistent"), 404)
end
Running Tests
One focused test file
cd /path/to/app
mix test test/path/to_test.exs
all tests
make test