Gleam Testing Skill
This skill guides Claude Code through testing Gleam applications.
Primary Sources
- •Gleeunit Documentation - Test framework
- •Let Assert - Gleam Tour - Assertion syntax
- •Testing Guide - Comprehensive testing
- •Test Timeouts - Timeout configuration
- •Birdie - Snapshot testing
- •Glacier - Interactive testing
- •QCheck - Property-based testing
- •Gleamy Bench - Benchmarking
Quick Reference
Test Command
gleam test # Run all tests gleam test --target erlang # Erlang target only gleam test --target javascript # JavaScript target only
Test File Structure
project/ ├── test/ │ ├── project_name_test.gleam # Main test file │ ├── feature_a_test.gleam # Feature tests │ └── feature_b_test.gleam
Critical Rules
Use let assert NOT should (MANDATORY)
The gleeunit/should module is deprecated.
See examples: Testing Practices
Test Function Naming (MANDATORY)
Functions ending in _test are automatically discovered and run.
pub fn my_feature_test() {
// Test implementation
}
Common Testing Patterns
Unit Testing
pub fn add_test() {
let assert 5 = add(2, 3)
let assert 0 = add(-1, 1)
}
Testing Result Types
pub fn parse_success_test() {
let assert Ok(value) = parse("valid input")
let assert expected_value = value
}
pub fn parse_failure_test() {
let assert Error(Nil) = parse("invalid input")
}
Testing Custom Types
pub fn user_creation_test() {
let user = create_user("alice@example.com")
let assert Active(_, email) = user
let assert "alice@example.com" = email
}
Testing Error Variants
pub fn error_handling_test() {
let assert Error(NotFound(id)) = fetch_user("invalid-id")
let assert "invalid-id" = id
}
Advanced Testing
Test Timeouts (Erlang Target)
For tests that need more than 5 seconds:
See: Gleam Test Timeouts
Property-Based Testing
For testing properties that should hold for all inputs:
See: gleam_qcheck Documentation
Example use cases:
- •Testing that
reverse(reverse(list)) == list - •Verifying encoding/decoding round-trips
- •Checking mathematical properties
Snapshot Testing
For testing rendered output:
See: Birdie Documentation
Use cases:
- •HTML rendering
- •JSON API responses
- •Formatted text output
Interactive Testing
For development workflows with fast feedback:
Testing Web Applications
HTTP Request Testing
For Wisp applications: See: Wisp Testing
Database Testing
Patterns for testing with databases:
- •Use test databases
- •Wrap tests in transactions (rollback after)
- •Use fixtures for test data
- •Consider using SQLite in-memory for fast tests
Mocking External Services
Gleam doesn't have built-in mocking. Patterns:
- •Dependency injection via function parameters
- •Test doubles (implement same type)
- •Behavior parameterization
Testing OTP Applications
Actor Testing
import gleam/otp/actor
pub fn actor_behavior_test() {
let assert Ok(actor.Started(subject, _)) = start_my_actor()
// Test message handling
let response = actor.call(subject, waiting: 100, sending: fn(s) { GetState(s) })
let assert expected_state = response
}
See: OTP Development
Supervision Testing
Test that supervisors:
- •Start children correctly
- •Restart children on failure
- •Respect max restart limits
Performance Testing
Benchmarking
For performance measurements:
See: gleamy_bench Documentation
Use cases:
- •Comparing algorithm implementations
- •Measuring optimization impact
- •Profiling hot code paths
Test Organization
Test Modules
Organize tests by feature or domain:
test/ ├── auth_test.gleam # Authentication tests ├── user_test.gleam # User management ├── api_test.gleam # API endpoints └── integration_test.gleam # Integration tests
Test Helpers
Create helper functions in test modules:
// test/test_helpers.gleam
pub fn create_test_user() -> User {
User(id: "test-id", email: "test@example.com")
}
pub fn with_database(test: fn(Connection) -> a) -> a {
let assert Ok(conn) = setup_test_db()
let result = test(conn)
teardown_test_db(conn)
result
}
Cross-Platform Testing
Tests run on both Erlang and JavaScript targets by default. Be aware of platform differences:
- •Test timeouts only work on Erlang
- •Some external functions behave differently
- •Platform-specific tests can use
@targetattribute
See: External Functions
CI/CD Integration
GitHub Actions
Example workflow:
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: "27.0"
gleam-version: "1.10.0"
- run: gleam deps download
- run: gleam test
- run: gleam format --check src test
Test Coverage
Currently, Gleam doesn't have built-in coverage tools. Options:
- •Use Erlang's cover tool
- •Monitor test comprehensiveness manually
- •Focus on critical path coverage
Common Testing Patterns
Table-Driven Tests
pub fn multiple_cases_test() {
let cases = [
#("input1", "output1"),
#("input2", "output2"),
#("input3", "output3"),
]
list.each(cases, fn(case) {
let #(input, expected) = case
let assert expected = my_function(input)
})
}
Setup and Teardown
pub fn test_with_setup() {
// Setup
let resource = create_resource()
// Test
let assert Ok(result) = use_resource(resource)
// Teardown (using defer-like pattern)
cleanup_resource(resource)
}
Test Quality Guidelines
✅ Good tests:
- •Test one thing
- •Have clear names
- •Are independent (no shared state)
- •Are fast (when possible)
- •Are deterministic
❌ Avoid:
- •Testing implementation details
- •Shared mutable state
- •Flaky tests (timing-dependent)
- •Tests that are hard to understand
Remember: Tests are documentation. Write them clearly and maintain them carefully.