Under the hood of a Gleam test-framework

eliasson1 pts0 comments

Under the hood of a Gleam test-framework - Markus EliassonUnder the hood of a Gleam test-framework<br>During spring and summer I have been busy building a small test-framework in Gleam. Let's open the hood and see how it is designed, and why I designed it the way I did. Hopefully this can inspire you to try out Gleam, Garanti or building your own thing.<br>7 August, 2026If you were to build a test-framework in your favourite language, how would it look? What features would you add?<br>How would you implement the test execution? Should tests be able to share data or setup code?

These are all questions I have been thinking about lately as I have been busy implementing a small test-framework for<br>Gleam.

Gleam is the programming language I enjoy spending my time with most recently. I have mostly been using it to do<br>web stuff, so far so I wanted to build something different.

Even if you have little to no experience with Gleam the article should still be digestible. The language is quite<br>simple (in the Rich Hickey way1) and the tool-chain makes Gleam easy to use.

1. Obligatory viewing Go ahead, I'll wait.<br>So far, the user satisfaction has been through the roof, 100% happy users!

Yes, as you probably guessed, I am the only user so far. Maybe this article can inspire someone else to try it and<br>give me some feedback though!

Show me the code

This is a snippet from one of my other hobby projects. It is a test suite used to verify that resolving a path using<br>a root path resolves correctly.

pub fn parse_path_segments_suite() {<br>Suite("When parsing a path into segments", [<br>Test("an empty path has no segments", fn() {<br>segments("")<br>|> expect.to_be_equal([])<br>}),

Test("the root path has no segments", fn() {<br>segments("/")<br>|> expect.to_be_equal([])<br>}),

Test("a single segment path is split", fn() {<br>segments("/posts")<br>|> expect.to_be_equal(["posts"])<br>}),

Test("nested segments are split in order", fn() {<br>segments("/posts/hello-world")<br>|> expect.to_be_equal(["posts", "hello-world"])<br>})<br>])

fn segments(raw: String) -> List(String) {<br>request.parse_path(raw, None).segments // }

Running this when everything is working produces the following output:

$ gleam test<br>Resolving versions<br>Compiled in 0.07s<br>Running paper_test.main<br>Discovered 1 suite(s).<br>Analysed suites: No problems found.<br>Running 1 suites...<br>Suite When parsing a path into segments completed successfully with 4 test(s)<br>Test an empty path has no segments completed successfully<br>Test the root path has no segments completed successfully<br>Test a single segment path is split completed successfully<br>Test nested segments are split in order completed successfully<br>All 4 test(s) passed!

If we break the implementation, it fails loudly:

$ gleam test<br>Resolving versions<br>Compiled in 0.07s<br>Running paper_test.main<br>Discovered 1 suite(s).<br>Analysed suites: No problems found.<br>Running 1 suites...<br>Suite When parsing a path into segments completed with 4 failure(s)<br>Test an empty path has no segments failed with:<br>Expected [""] to equal [].<br>Actual: [""]<br>Expected: []

Test the root path has no segments failed with:<br>Expected ["", ""] to equal [].<br>Actual: ["", ""]<br>Expected: []

Test a single segment path is split failed with:<br>Expected ["", "posts"] to equal ["posts"].<br>Actual: ["", "posts"]<br>Expected: ["posts"]

Test nested segments are split in order failed with:<br>Expected ["", "posts", "hello-world"] to equal ["posts", "hello-world"].<br>Actual: ["", "posts", "hello-world"]<br>Expected: ["posts", "hello-world"]<br>4 of 4 test(s) failed.

In the console, the actual value will be printed in bold and red. Whereas the expected value will be in bold and green.

But why?

There is already a test-framework in Gleam. The gleeunit is even part of the official<br>tool-chain, and when you scaffold a new project you get a placeholder test2 as well. Could I not just use<br>that?

2. Greeting Joe. A nice homage to the Erlang roots!<br>Sure. But I wanted to build something small where I could try out OTP (the concurrency features in Gleam and Erlang)<br>and I wanted a test-framework that has matchers for common asserts and not only using Gleam's built in assert like<br>gleeunit does.

There is absolutely nothing wrong with gleeunit, or with not using matchers. You can write good tests in either, it<br>is just that I prefer matchers.

What makes a good test?

Writing good tests is quite hard, I think. When you have all the context loaded in your head and are writing the test<br>it is a lot easier to spot a failing detail and immediately know what's wrong. Come back to the same test two years later<br>(heck, even two weeks) and it is a lot harder!

I would say that a good test is 50/50 between reading the test code and reading the test failure message.

The test code should clearly communicate the intent3 of the test. The situation / context the test<br>operates in, what the test does, and finally what the test expects to happen.

3. Funny enough this is not my first test-framework. A colleague and I wrote small one for Scala a few<br>years ago. Guess what we...

test segments gleam path posts framework

Related Articles