Build your own test runner
Published: 2022-11-30 by Lars tooltestcode
This blog post describes how to build a test runner. Even though plenty of test runners probably already exist for your platform, understanding how to build your own test runner from scratch is useful. Having a good understanding of how the tools we use work under the hood allows us to better leverage their strengths and work around their limitations. Also, new platforms pop up all the time, or you might have to work on an old platform without a good test runner, and then someone will have to create a test runner for that platform. Using the knowledge from this post, that person could be you!
So what is a test runner? Obviously, it is something that will run our tests and then report on the results. But modern test runners tend to bundle a huge amount of additional functionality, making it hard to see what the "core" test runner responsibility is. When learning how to build a test runner, we want to focus on those core responsibilities.
So to describe how to build a test runner, we will apply two design principles:
- Keep it simple: only include features in the test runner that must be part of the test runner itself.
- Full source code: include all the code needed by the test runner without using any external libraries (with one exception), except standard libraries provided by the platform itself.
The post is divided into two parts:
In part 1 we will build a minimalistic test runner for the Node.js platform, written in plain JavaScript, and annotated with TypeScript types using JSDoc. To keep things simple we will only implement support for modern ES modules, not CommonJS or any other module system.
Later, in part 2, we will describe how other tools can be combined with our minimalistic test runner to provide the remaining useful features around running tests.
The source code for the test runner descibed here plus all the example code can be found on GitHub.
The two parts are divided into the following sections:
Part 1 - A minimalistic test runner
- Registering and running individual tests
- Failing tests
- Waiting for asynchronous tests
- Grouping tests
- Setting up and tearing down
- Loading test files
- Running tests in parallel
- Reporting results
- Finding test files
- Writing assertions
- Expecting a test to fail
- Skipping a test
- Repeating a test
- Timing out tests
- Having tests in source files
- Isolating tests from each other
- Mocking timers
- Mocking objects
- Mocking modules
- Emulating a browser
- Reporting coverage
- Transpiling
- Watching
- Debugging
Related work
This work is inspired by great guides on how to build other tools that we use all the time:
- Version control: Building Git by James Coglan
- Web browser: Web Browser Engineering by Pavel Panchekha & Chris Harrelson
Christoph Nakazawa also recently wrote a detailed blog post on Building a JavaScript Testing Framework where he describes how to build a Jest-like test runner on top of the many modules that make up the inner workings of Jest.
Continue
Continue with