> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# How Bazel runs tests

> Understand how Bazel runs tests as a special kind of action, the role of the test runner, the Test Encyclopedia, and patterns for hermetic external services.

Bazel models tests as a special case of running programs, where the exit code matters.
So you can think of `bazel test my_test` as syntax sugar for `bazel build my_test && ./bazel-bin/my_test`

The "program" run is usually a "Test Runner" from your language ecosystem, such as JUnit, `pytest`, `mocha`, etc. This is unlike most build systems, where the developer interacts directly with the test runner CLI.

However, it can also be a shell script or any other program you write. With Bazel, it's often useful to write your own Test Runner rather than build your test in some existing test/assertion framework since Bazel handles all the mechanics of including your test in the build process.

## The test encyclopedia

When Bazel’s interaction with the test runner doesn’t do what you expected, you may need to consult the [Test Encyclopedia](https://bazel.build/reference/test-encyclopedia), described as "an exhaustive specification of the test execution environment".

This contract between Bazel and your test runner process will often resolve a dispute over why your test isn't working the way you expect under Bazel.

## External services

Tests often want to connect to services/datasources as part of the "system under test".
With some CI tools or custom scripts, you might do this outside the build tool, like so:

1. Start up some services or populate a database
2. Run the entry point for the testing tool
3. Clean up

Bazel does ***not*** support this model.
Bazel tests are just programs that exit 0 or not, and Bazel has no "lifecycle" hooks to run some setup or teardown for specific test targets.

You could script around Bazel, the same as in the scenario above, by starting some services before running `bazel test` and then shutting them down at the end.
However, this doesn't work well with remote execution. It also assumes that concurrent tests will be isolated from each other when accessing the shared resource. It means you startup the services even if Bazel doesn't execute any tests because they are cache hits.

Ideally, tests are hermetic.
That means they depend only on declared inputs, which are files.
If a test needs to connect to a service, you could invert the above model.

The testing tool runs the test, which sets up the environment and tears it down.
[Testcontainers](https://www.testcontainers.org/) is a great library for using Docker containers as a part of the system under test.
You may also explore [rules\_itest](https://github.com/dzbarsky/rules_itest), which provides Bazel-native support for integration-style tests.
