Busted: Lua Unit Testing with Readable Specs
Elegant Lua unit testing.
At a glance
- What is it?
- Busted is an MIT-licensed Lua unit testing framework for developers working with Lua 5.1 or later, LuaJIT 2.0.0 or later, and Moonscript. It combines readable specs, extensible assertions, spies, tagging, several output formats, and container and CI execution options.
- Who is it for?
- Busted fits Lua libraries and applications that want a conventional unit testing framework with readable specs and manageable output selection. It is a poor fit when a project cannot add Lua dependencies or when a container must supply every runtime dependency.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 59 days ago.
- What is it written in?
- Mainly Lua, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Busted's place in Lua project testing
Busted solves the problem of organizing repeatable unit tests for Lua code. It is aimed at developers who want tests to describe behavior directly, including named contexts, individual examples, assertions, and functional test helpers. The README specifies support for Lua >= 5.1, luajit >= 2.0.0, and moonscript, so the framework is not tied to one interpreter version or one source language.
Its central design choice is a spec structure built from `describe` and `it`. A developer can place a description around a group of examples, then state the expected behavior inside each example. Assertions are available through Lua-style method calls, including negation and chaining. The documentation also shows spies that can observe calls to a module function and verify the arguments passed to them.
This makes Busted relevant to Lua library maintainers who want a test suite that can run locally, in Docker, or in CI. It is less suitable for a codebase that does not use Lua-compatible tooling, because the repository supplies a Lua testing framework rather than a language-neutral test runner. The documented Docker workflow also has a dependency constraint, discussed later in this article.
How Busted organizes specs and assertions
A Busted spec nests test contexts with `describe` and defines individual tests with `it`. Each callback contains the code or assertion sequence for one behavior. This creates a readable hierarchy in the source file, although the README does not document alternative discovery or configuration mechanisms beyond the examples and the documented CLI commands.
Assertions cover ordinary value checks as well as Lua-specific concerns. The example uses `assert.truthy`, `assert.falsy`, and `assert.error` for predicates and error conditions. It uses `assert.same` for a deep comparison and `assert.is_not.equals` for a comparison that should fail when two separate tables contain equivalent fields. The example also demonstrates `assert.unique` for checking a collection.
Busted supports chained assertions and negations, such as `assert.is_not.equal`. The README describes the assertion library as extensible, so project-specific assertions can be added rather than keeping every test helper inside application code. It also documents a modular output library. Available formats include pretty and plain terminal output, JSON with and without streaming, and TAP-compatible output. The exact choice of formatter is therefore a project-level decision rather than a property of the test definitions themselves.
Installing Busted and running the repository specs
The README does not provide a complete command for installing the released Busted package into a new Lua environment. Its testing instructions begin by assuming that LuaRocks is already installed, then install the Moonscript dependency and build the project. The commands below are the documented core-testing workflow. Run them from the repository source directory.
Install the extra testing dependency first. This command installs `moonscript` through LuaRocks.
luarocks install moonscriptReinstall the local Busted package, build it, and run the repository's specs. The second command removes the existing package, the third builds the current source tree, and the fourth executes the `spec` directory.
luarocks remove busted --force
luarocks make
busted specThe documentation says to use this workflow when reinstalling and testing Busted itself. It does not state the expected pass count or describe the output produced by a successful run, so those details should not be inferred. For an application project, the README also does not give a separate application setup procedure beyond installing Busted as a LuaRocks dependency or using the documented container image.
Running Busted through Docker
Busted can run as a standalone Docker container. This is useful when a project needs an isolated Lua test environment, but the README identifies a clear limitation: many applications require additional dependencies that must be installed inside the container. The image includes LuaRocks, and the base image is Alpine Linux, so project dependencies can be added with LuaRocks and system packages can be added with `apk add`.
Build the image from a local Busted source checkout with the documented command. The resulting image is tagged `HEAD`.
docker build -t ghcr.io/lunarmodules/busted:HEAD .Alternatively, pull the prebuilt `latest` image. The README says that a tagged release can be substituted where applicable.
docker pull ghcr.io/lunarmodules/busted:latestRun the container against the current project directory, or point it at the `specs` directory. The volume mount exposes the project at `/data`, which matches the image's working directory.
docker run -v "$(pwd):/data" ghcr.io/lunarmodules/busted:latestFor a single directory, use this form. The README presents it as the way to run one directory rather than the entire project.
docker run -v "$(pwd):/data" ghcr.io/lunarmodules/busted:latest specsThe container entry point is documented in the repository Dockerfile as `busted --verbose --output=gtest`. Consequently, the image is not merely a generic Lua shell. Its default behavior includes verbose output and the `gtest` formatter.
Busted in GitHub Actions with tags and output selection
The README provides a GitHub Actions workflow, which gives Busted a direct path into CI. The basic job checks out the repository and invokes the `lunarmodules/busted@v0` action on pushes and pull requests. This is useful for projects that already want to run their own specs in a hosted runner without manually installing the framework.
The documented action configuration runs `busted --verbose` by default, with `.` as the default input for the path. A project can replace that default with its own arguments. For example, the README shows a tag selector:
name: Busted
on: [push, pull_request]
jobs:
sile:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Run Busted
uses: lunarmodules/busted@v0
with:
args: --tags=MYTAGSTags are attached to blocks of tests, and the README states that arbitrary groups can be selected when running tests. This supports workflows such as running a smaller suite during rapid changes or selecting tests by category. The repository also documents JSON and TAP-compatible output. TAP is relevant to CI because it is designed for compatibility with many CI servers, while JSON can be selected when another system needs machine-readable results. The exact availability of each option in a particular runtime should be checked against the version being installed.
Spies, maintenance, and the limits of the container workflow
Busted includes spies for observing function calls. In the README example, a module is loaded, `spy.on` replaces observation of the `greet` function, the function is called with `Hi!`, and assertions verify that it was called and called with that argument. This is useful for functional tests where the test cares about collaboration with a dependency or collaborator rather than only the final return value.
The repository is not archived. Its last push was on 2026-08-25, and the release list includes `v2.3.0` dated 2026-01-07, after `v2.2.0` and `v2.1.2` from 2023. The repository therefore shows a release after the earlier versions, but the README does not document a compatibility policy, migration guide, or upgrade procedure. License changes or interpreter changes should be checked against the `LICENSE` file and release contents before changing an existing suite.
Docker is the most obvious trade-off. The README calls it somewhat limited for projects that need extra dependencies, because those dependencies must be added inside the container. It describes Docker as most advantageous for pure-Lua projects with no dependencies. A small library may therefore use the prebuilt image directly, while an application with native modules, system libraries, or a large dependency tree will need a tailored image. The container also uses an Alpine-based environment, so packages and native extensions that depend on another Linux distribution are not interchangeable without verification.
For comparison, a plain Lua assertion script can test isolated functions without Busted's `describe` and `it` structure, tagging, spies, or selectable output formats. That approach can be simpler for a very small codebase, but it does not provide the same documented spec organization or CI output options. A project that needs Busted's grouping and reporting features has more dependency and version surface to manage.
Editorial conclusion
Busted fits Lua libraries and applications that want a conventional unit testing framework with readable specs and manageable output selection. It is a poor fit when a project cannot add Lua dependencies or when a container must supply every runtime dependency. Before adoption, verify the required LuaRocks setup, the intended output format, the tagging strategy, and whether the Docker image includes the project dependencies.
Frequently asked questions
How do I install Busted for a Lua project?
The README assumes LuaRocks is installed, but it does not provide a complete command for installing the released Busted package into a new project. It documents `luarocks make` for building the local source tree and provides Docker commands for a prebuilt container.
Which Lua versions does Busted support?
Busted supports Lua >= 5.1, luajit >= 2.0.0, and moonscript, according to the README.
Can Busted run tests in Docker and CI?
Yes. The README documents building or pulling `ghcr.io/lunarmodules/busted:latest`, mounting the project at `/data`, and using `lunarmodules/busted@v0` in a GitHub Actions workflow. Projects with additional dependencies may need to install them inside the container.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/lunarmodules-busted)Was this useful?