| name | gleam-testing |
| description | Guides Claude through testing Gleam applications with gleeunit. Use when writing unit tests, integration tests, or property-based tests. Always use let assert, NOT deprecated should module. |
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
gleam test --target erlang
gleam test --target javascript
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
}
See: Gleeunit Documentation
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:
See: Glacier Documentation
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
@target attribute
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
See: Writing Gleam - CI/CD
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.