Skip to content

test

Utilities for writing and running test suites.

dolang -m test runs the tests under its path arguments with run. Its --jobs, --module-jobs and --timeout options set the keywords of the same names, and --no-capture turns off capture.

--filter takes a glob matched against module/name, where module is the test file's path without its extension. The repeatable --tags option splits each occurrence on commas: alternatives in one occurrence are ORed, while occurrences are ANDed. Prefix a tag with ! to require its absence. Matching is exact and case-sensitive.

--tags !windows,!macos means “not Windows OR not macOS.” Use --tags !windows --tags !macos to exclude both.

The repeatable --id option selects tests by exact ID, with no glob syntax to escape. It combines with --filter and --tags, all of which must match.

Listing Tests

--list loads each module with list and reports the selected tests without running them. --jobs and --no-capture don't apply. The exit status is one when a module fails to compile or load, and zero otherwise, including when a module skips while loading.

By default the list is a report on the console. --format json instead writes one JSON document to standard output, or to the file given by --output:

{
  "version": 1,
  "modules": [
    {
      "path": "test/foo.dol",
      "module": "test/foo",
      "status": "loaded",
      "tests": [
        {
          "id": "test/foo/connects/backend=sqlite",
          "module": "test/foo",
          "name": "connects/backend=sqlite",
          "base": "connects",
          "params": [["backend", "sqlite"]],
          "tags": ["slow"],
          "location": {"file": "test/foo.dol", "line": 12, "column": 0, "len": 12}
        }
      ]
    },
    {
      "path": "test/bar.dol",
      "module": "test/bar",
      "status": "failed",
      "error": {"kind": "compile", "message": "...", "diagnostics": [...]}
    }
  ]
}
  • version changes when the format changes incompatibly.
  • Modules appear in path order, and tests in registration order. Paths are as given on the command line, with directories expanded.
  • status is loaded, failed, skipped or ignored. A skipped or ignored module has a message, which may be null.
  • A test's fields are those of TestInfo. location is null when unknown.
  • A failed module's error has a kind of compile or load and a message. A compile error lists diagnostics, each with a severity (error or warning), message and location. A load error has rendered, the error as the run report prints it, with its backtrace. An output field holds what the module wrote while loading, when it wrote anything.
  • Locations are zero-based, with columns and lengths in characters, as in inspect.Location.

Progress Events

--format jsonl runs the tests and writes progress events to standard output, or to the file given by --output, in place of the report. Each line is one JSON object, written as events happen, so events from concurrent modules and tests interleave. Output is always captured, so --no-capture is rejected. The exit status is the same as for the report.

{"event": "run-start", "version": 1, "modules": 1}
{"event": "module-start", "path": "test/foo.dol", "module": "test/foo"}
{"event": "module-end", "path": "test/foo.dol", "module": "test/foo", "status": "loaded", "tests": [...]}
{"event": "test-start", "id": "test/foo/adds", "module": "test/foo", "name": "adds", ...}
{"event": "test-end", "id": "test/foo/adds", "outcome": "failed", "duration": 0.002, "message": "assertion failed: 3 == 4", "error": {...}, "failure_location": {...}}
{"event": "run-end", "passed": 0, "failed": 1, "skipped": 0, "ignored": 0, "status": 1}

Each event's event field names it:

  • run-start comes first, with the format version and the number of modules.
  • module-start has the module's path and module.
  • module-end follows when the module has loaded, or failed to. Its fields are those of a module in the --list document.
  • test-start has the fields of a test in the --list document.
  • test-end has the test's id, an outcome of passed, failed, skipped or ignored, and its duration in seconds. Ignored tests are reported, unlike in the report. Unless the test passed, it also has:
    • message: the Skip or Ignore message, which may be null, or the string form of the error.
    • failure_location: the location of the innermost call in the test's file when the error was raised, or null. This is the failing line even when the error comes from an assertion function, a fixture or a helper.
    • output: what the test wrote, when it wrote anything.
    • error, for a failure: the error's type, the rendered error as the report prints it, and the backtrace, innermost call first. Each frame has the module, receiver, method and location of inspect.Frame. An Assert error from a comparison adds its expected and actual values.
  • run-end comes last, with the number of tests passed, failed, skipped and ignored, and the exit status.

Types

TypeDescription
Assert Raised when an assertion fails.
Ignore Raised to omit a test case from the report.
Skip Raised to skip a test case.
@Tagged[T] A parametrize value carrying tags, made by tagged.
TestInfo Read-only metadata for a discovered test.

Functions

assert cond …

Asserts that cond is truthy.

Parameters

NameTypeDescription
cond Condition to test.
msg? Str Message to add to the failure.

Errors

Assert if the assertion fails.

assert_eq left right …

Asserts that left == right.

Parameters

NameTypeDescription
left Actual value.
right Expected value.
msg? Str Message to add to the failure.

Errors

Assert if the assertion fails.

assert_ne left right …

Asserts that left != right.

Parameters

NameTypeDescription
left Actual value.
right Value it must differ from.
msg? Str Message to add to the failure.

Errors

Assert if the assertion fails.

assert_not cond …

Asserts that cond is falsy.

Parameters

NameTypeDescription
cond Condition to test.
msg? Str Message to add to the failure.

Errors

Assert if the assertion fails.

assert_throws[E] type block … -> E

Asserts that block raises an error of type, and returns the error.

Parameters

NameTypeDescription
type Type[E] Error type expected, or a supertype of it.
:str? Str Expected string form of the error.
:msg? Str Message to add to the failure.
block (() -> Value) Block to run.

Errors

Assert if the assertion fails.

assert_type[T] expected value …

Asserts that value is an instance of expected or a subtype of it.

Parameters

NameTypeDescription
expected Type[T] Expected type.
value Value to test.
msg? Str Message to add to the failure.

Errors

Assert if the assertion fails.

fixture wrap -> ((Value) -> Value)

Defines a test fixture. wrap should be a function which accepts a block and invokes it with surrounding setup and teardown logic. wrap receives any trailing keyword parameters supplied by parametrize (or by an outer fixture) after block and should forward them to block — typically via a variadic ...rest parameter — so they reach the test function. wrap may also pass its own additional keyword parameters to block to inject values into the test.

Example

#[fixture]
def example_fixture block ...rest
  setup()
  try
    block(...rest)
  finally
    teardown()

#[test]
#[example_fixture]
def example_test()
  do_something()

ignore …

Omits the current test from the report by raising Ignore.

Parameters

NameTypeDescription
msg? Str Reason to record.

list *paths … -> Int

Discovers tests under the given files and directories without running them.

Each module is compiled and loaded as run loads it, and the tests it registers that pass filter are reported in file order, then in registration order. Output a module writes while loading is captured. Modules that fail to compile or load, or that skip while loading, are reported alongside the tests.

The human-readable report goes to the console. The JSON document is described in the module documentation.

Parameters

NameTypeDescription
:module_jobs? Int Maximum concurrent modules.
:filter? ((TestInfo) -> Bool) Predicate receiving a TestInfo. Defaults to accepting every test.
:timeout? Int Module-load timeout in seconds.
:format? (:HUMAN: | :JSON:) :HUMAN: for a report on the console, or :JSON: for a JSON document.
:output? (Str | fs.Path | nil) File to write the JSON document to instead of standard output.
*paths (Str | fs.Path) Test file or directory.

Returns

One when any module fails to compile or load, otherwise zero.

parametrize ...axes -> ((Value) -> Value) overload 1 of 2

Registers one or more parametrize axes on a test. Each keyword argument names an axis under which its value is passed to the decorated test function (and to any fixture that declares it). Stacks with other parametrize decorators, and composes freely with #[fixture] decorators; the cartesian product is taken over every axis registered by any application.

Because decorators apply bottom-to-top, axes accumulate in closest-to-def-first order (axes from one decorator are ordered as written); this affects only the generated case names ($base_name/$axis1=$v/$axis2=$v/...).

Parameters

NameTypeDescription
...axes Iterable[Value] An axis name paired with an iterable of raw values and/or tagged(value, ...tags) wrappers for that axis.

Example

#[test]
#[parametrize backend: [sqlite_conn, tagged(postgres_conn, "slow")]]
def connects :backend
  backend.ping()

parametrize func ...axes overload 2 of 2

Registers parametrize axes on a test function directly, returning the decorated test for test.

Parameters

NameTypeDescription
func Test function, or a test already decorated with parametrize or a fixture.
...axes Iterable[Value] An axis name paired with an iterable of raw values and/or tagged(value, ...tags) wrappers for that axis.

run *paths … -> Int

Discovers and runs tests under the given files and directories.

A directory is searched recursively for .dol files.

With format: :JSONL:, progress events go to standard output, or to output, in place of the report. The events are described in the module documentation.

Parameters

NameTypeDescription
:jobs? Int Maximum concurrent tests.
:module_jobs? Int Maximum concurrent modules.
:filter? ((TestInfo) -> Bool) Predicate receiving a TestInfo. Defaults to accepting every test.
:timeout? Int Per-test and module-load timeout in seconds.
:capture? Bool Capture output and show it for failures.
:format? (:HUMAN: | :JSONL:) :HUMAN: for a report on the console, or :JSONL: for progress events.
:output? (Str | fs.Path | nil) File to write progress events to instead of standard output.
*paths (Str | fs.Path) Test file or directory.

Errors

ValueError if format is :JSONL: and capture is false.

Returns

Zero when all selected tests pass, or one when any module or test fails.

skip …

Skips the current test by raising Skip.

Parameters

NameTypeDescription
msg? Str Reason to report.

tagged[T] value *values -> Tagged[T]

Attaches tags to a single parametrize value, honored only in cases that select it.

Parameters

NameTypeDescription
value T The parametrize value.
*values Str Tags to attach.

Example

#[parametrize backend: [sqlite_conn, tagged(postgres_conn, "slow")]]

tags *values

Adds tags to tests subsequently registered in the current module.

Repeated calls accumulate tags. Module tags precede tags supplied directly to test; order and duplicates are preserved.

Parameters

NameTypeDescription
*values Str Tag to add.

Example

tags "integration" "linux"

#[test tags: ["slow"]]
def connects()
  connect()

test … -> ((Value) -> Value) overload 1 of 2

Returns a decorator that registers a zero-argument test function.

Parameters

NameTypeDescription
:name? Str Reporting name. Defaults to the test function's string form.
:tags? Iterable[Str] Tags to attach. Order and duplicates are preserved.

Example

#[test name: "connects" tags: ["integration", "linux"]]
def connects_to_service()
  connect()

test[F] func … -> F overload 2 of 2

Registers a zero-argument test function, returning it.

Parameters

NameTypeDescription
:name? Str Reporting name. Defaults to str(func).
:tags? Iterable[Str] Tags to attach. Order and duplicates are preserved.
func F Test function, or a test decorated with parametrize or a fixture.