In the early days of computing, there were no automated testing tools. Programmers had to rely on manual debugging, often using print statements or other manual methods to identify and fix issues in their code. This was a time-consuming and error-prone process. Test-driven development (TDD) gained prominence in the early 2000s—a software development practice used by developers to write tests for a piece of code before writing the actual code. The tests guide the development process and help ensure the code works as expected.
Bun appears to draw inspiration from this shift towards a more systematic and automated approach to testing. Jest, a popular testing framework, is a reference for Bun testing features. It offers features like snapshot testing, built-in mocking, and other capabilities to streamline the testing workflow. In addition, Bun provides a fast, built-in Jest-compatible test runner. With Bun, developers can enjoy the following features:
TypeScript and JSX support
Lifecycle hooks for testing components
Snapshot testing for tracking and validating UI component changes
UI and DOM testing capabilities
Watch mode with --watch
for continuous testing during development
Script preload with --preload
to enhance test performance and efficiency
Tests in Bun are written in JavaScript or TypeScript and use a familiar Jest-like API. We can create test files with names that match specific patterns to be automatically discovered by the test runner. Test files typically have names like *.test{js|jsx|ts|tsx}
or *.spec.{js|jsx|ts|tsx}
but they can be *_test.{js|jsx|ts|tsx}
or *_spec{js|jsx|ts|tsx}
.
To run tests using Bun, we employ the following command:
bun test
The test runner explores the working directory to locate files matching the prescribed test file patterns and execute the tests within. Here is an example of the outcome when using the bun test
command with the test file shown above:
import { expect, test } from "bun:test";test("5 + 5", () => {expect(5 + 5).toBe(10);});
Let’s break down the provided test:
Line 1: We import the expect
and test
functions from the "bun:test"
module.
Line 3: We write a test case with the description "5 + 5"
. The arrow function (() => {
) is the test function executed when this test case runs.
Line 4: Within the test function, we use the expect
function to make an assertion. It checks whether the result of the expression 5 + 5
is equal (toBe(10)
) to 10. In other words, it verifies that the sum of 5 and 5 equals 10.
In the above example, a simple test is executed successfully and passed. If a test encounters a failure, the outcome would be different. Let’s see how a test failure scenario unfolds:
import { expect, test } from "bun:test";test("5 + 5", () => {expect(6 + 5).toBe(10);});
As demonstrated, when a test fails, we can precisely pinpoint the location of the failure and understand the reason behind it. This feature provides developers a valuable tool for diagnosing and resolving issues promptly.
Bun’s test runner processes all our tests sequentially within a single environment. This implies that tests are executed one after the other. When a test run is completed, the test runner provides an exit code, which can be vital for automating the build and CI/CD processes to determine the overall test suite outcome.
An exit code of
In the following testing setup, we implement similar test cases in two different files to showcase how the bun test
efficiently manages and executes tests across multiple files. Let’s observe how the exit code varies based on test outcomes.
import { expect, test } from "bun:test";test("5 + 5", () => {expect(6 + 5).toBe(10);});
In this case, a non-zero exit code indicates the failure of a test.
Now, let’s fix the first test to make it pass:
import { expect, test } from "bun:test";test("5 + 5", () => {expect(6 + 5).toBe(11);});
Here, we obtain an exit code of bun test
command to customize and control the test execution process.
Flag | Description |
| Used for script preloading |
| Specifies a per-test timeout in milliseconds |
| Runs each test a specified number of times (n) |
| Aborts the test run early after a predetermined number of test failures |
| Watches for changes and reruns tests |
| Updates snapshots |
| Only runs tests that are marked with |
| Runs tests defined using |
Running tests with Bun is exceptionally straightforward, and its compatibility with Jest makes it an outstanding choice as a testing framework for our projects. However, it’s important to note that Bun offers a rich array of features beyond what we’ve covered. These include capabilities such as mock tests, watch mode for continuous testing during development, and more. Delving into these advanced features can further enhance our testing workflow and productivity, making Bun a versatile and powerful tool for comprehensive testing in our projects.