Testing in Gleam: How the Built‑In Test Runner Keeps Your Workflow Simple
Gleam ships a zero‑dependency test runner that discovers and runs tests in `test/` folders. Learn how to write, run, and tweak tests, and when the built‑in tools hit their limits.
04 Sept 2025, 18:30 UTC

Why a Built‑In Test Runner Matters
When a language ships with its own test runner, teams can avoid the friction of adding a third‑party dependency, configuring a separate test harness, and keeping the tooling stack minimal. Gleam’s gleam test does exactly that: it discovers test modules in test/, compiles them alongside your source, and runs them on the same runtime you use for production (Erlang VM or Node.js). This alignment guarantees that the code you test is compiled exactly the same way it will run in production.
Getting Started with gleam test
- Create a new project:
gleam new my_project - Navigate to the project root:
cd my_project - Add a test file under
test/– e.g.,test/math_test.gleam.
Running gleam test from the root will automatically find math_test.gleam, compile it, and execute the tests. No extra configuration is required.
Writing a Simple Test
Gleam’s standard library exposes the gleam/test module. The most common assertions are demonstrated below:
| Assertion | Purpose |
|---|---|
assert.equal(a, b) | Check value equality. |
assert.is_true(cond) | Assert a boolean condition. |
assert.unexpected_error(result) | Confirm a Result is Err and inspect the error. |
Example test file test/math_test.gleam:
import gleam/test
import my_project/math
pub fn test_add() {
assert.equal(math.add(2, 3), 5)
}
pub fn test_divide_error() {
let result = math.divide(1, 0)
assert.unexpected_error(result)
}
Notice that the test module is pub so the runner can import it. The functions themselves are also pub and start with test_ – this naming convention is optional but recommended for readability.
Flags and Customization
While the default behavior is often enough, gleam test offers flags to fine‑tune the run:
--test-dir <dir>– specify a custom test directory.--max-threads <n>– limit parallelism (useful for CI limits).--log-level <level>– adjust verbosity (e.g.,debug,info).
Example:
gleam test --max-threads 4 --log-level info
To view all supported flags, run gleam test --help in the project root. The output will list current options and their defaults, which may vary slightly between Gleam releases.
Limitations and When to Look Beyond
Gleam’s built‑in runner is designed for unit and integration tests that compile to the same target as production. However, it does not support:
- Property‑based testing frameworks (e.g., QuickCheck).
- End‑to‑end browser or UI tests for JavaScript targets.
- Mocking of external services beyond simple function replacement.
If your project requires extensive mocking, property testing, or browser‑level validation, consider integrating a third‑party framework or writing custom scripts that invoke gleam test as part of a larger test pipeline.
Wrap‑Up
For most Gleam projects, the built‑in gleam test command and gleam/test module provide a lightweight, reliable foundation for unit testing. The tight coupling between compile target and test execution keeps the test environment faithful to production, and the minimal tooling footprint reduces maintenance overhead.
Next steps: add a few more test modules, experiment with the --max-threads flag in your CI, and if you hit the limits of the built‑in runner, explore property‑based testing libraries that can be used alongside gleam test.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.