Package Control

The official Sublime Text package manager.

TestManager

A test explorer and runner for Sublime Test 4

By cshreib (Corentin Schreiber)
Created July 14, 2024, last updated July 24, 2026.

JunMayAprMarFebJan Dec2025 NovOctSepAugJul 2026-W30 | installs: 0 | removals: 0 | upgrades: 2 2026-W30 | installs: 0 | removals: 0 | upgrades: 2 2026-W30 | installs: 0 | removals: 0 | upgrades: 2 2026-W29 | installs: 1 | removals: 0 | upgrades: 0 2026-W29 | installs: 1 | removals: 0 | upgrades: 0 2026-W29 | installs: 1 | removals: 0 | upgrades: 0 2026-W28 | installs: 3 | removals: 1 | upgrades: 0 2026-W28 | installs: 3 | removals: 1 | upgrades: 0 2026-W28 | installs: 3 | removals: 1 | upgrades: 0 2026-W27 | installs: 0 | removals: 0 | upgrades: 0 2026-W27 | installs: 0 | removals: 0 | upgrades: 0 2026-W27 | installs: 0 | removals: 0 | upgrades: 0 2026-W26 | installs: 0 | removals: 0 | upgrades: 0 2026-W26 | installs: 0 | removals: 0 | upgrades: 0 2026-W26 | installs: 0 | removals: 0 | upgrades: 0 2026-W25 | installs: 0 | removals: 0 | upgrades: 1 2026-W25 | installs: 0 | removals: 0 | upgrades: 1 2026-W25 | installs: 0 | removals: 0 | upgrades: 1 2026-W24 | installs: 0 | removals: 0 | upgrades: 0 2026-W24 | installs: 0 | removals: 0 | upgrades: 0 2026-W24 | installs: 0 | removals: 0 | upgrades: 0 2026-W23 | installs: 0 | removals: 0 | upgrades: 0 2026-W23 | installs: 0 | removals: 0 | upgrades: 0 2026-W23 | installs: 0 | removals: 0 | upgrades: 0 2026-W22 | installs: 0 | removals: 0 | upgrades: 0 2026-W22 | installs: 0 | removals: 0 | upgrades: 0 2026-W22 | installs: 0 | removals: 0 | upgrades: 0 2026-W21 | installs: 1 | removals: 0 | upgrades: 0 2026-W21 | installs: 1 | removals: 0 | upgrades: 0 2026-W21 | installs: 1 | removals: 0 | upgrades: 0 2026-W20 | installs: 0 | removals: 0 | upgrades: 0 2026-W20 | installs: 0 | removals: 0 | upgrades: 0 2026-W20 | installs: 0 | removals: 0 | upgrades: 0 2026-W19 | installs: 0 | removals: 0 | upgrades: 0 2026-W19 | installs: 0 | removals: 0 | upgrades: 0 2026-W19 | installs: 0 | removals: 0 | upgrades: 0 2026-W18 | installs: 1 | removals: 0 | upgrades: 0 2026-W18 | installs: 1 | removals: 0 | upgrades: 0 2026-W18 | installs: 1 | removals: 0 | upgrades: 0 2026-W17 | installs: 0 | removals: 0 | upgrades: 0 2026-W17 | installs: 0 | removals: 0 | upgrades: 0 2026-W17 | installs: 0 | removals: 0 | upgrades: 0 2026-W16 | installs: 0 | removals: 0 | upgrades: 0 2026-W16 | installs: 0 | removals: 0 | upgrades: 0 2026-W16 | installs: 0 | removals: 0 | upgrades: 0 2026-W15 | installs: 0 | removals: 0 | upgrades: 0 2026-W15 | installs: 0 | removals: 0 | upgrades: 0 2026-W15 | installs: 0 | removals: 0 | upgrades: 0 2026-W14 | installs: 0 | removals: 0 | upgrades: 0 2026-W14 | installs: 0 | removals: 0 | upgrades: 0 2026-W14 | installs: 0 | removals: 0 | upgrades: 0 2026-W13 | installs: 1 | removals: 1 | upgrades: 1 2026-W13 | installs: 1 | removals: 1 | upgrades: 1 2026-W13 | installs: 1 | removals: 1 | upgrades: 1 2026-W12 | installs: 0 | removals: 2 | upgrades: 2 2026-W12 | installs: 0 | removals: 2 | upgrades: 2 2026-W12 | installs: 0 | removals: 2 | upgrades: 2 2026-W12 | installs: 0 | removals: 2 | upgrades: 2 2026-W11 | installs: 0 | removals: 0 | upgrades: 0 2026-W11 | installs: 0 | removals: 0 | upgrades: 0 2026-W11 | installs: 0 | removals: 0 | upgrades: 0 2026-W10 | installs: 0 | removals: 0 | upgrades: 0 2026-W10 | installs: 0 | removals: 0 | upgrades: 0 2026-W10 | installs: 0 | removals: 0 | upgrades: 0 2026-W09 | installs: 0 | removals: 0 | upgrades: 0 2026-W09 | installs: 0 | removals: 0 | upgrades: 0 2026-W09 | installs: 0 | removals: 0 | upgrades: 0 2026-W08 | installs: 0 | removals: 0 | upgrades: 0 2026-W08 | installs: 0 | removals: 0 | upgrades: 0 2026-W08 | installs: 0 | removals: 0 | upgrades: 0 2026-W07 | installs: 0 | removals: 0 | upgrades: 1 2026-W07 | installs: 0 | removals: 0 | upgrades: 1 2026-W07 | installs: 0 | removals: 0 | upgrades: 1 2026-W06 | installs: 0 | removals: 0 | upgrades: 0 2026-W06 | installs: 0 | removals: 0 | upgrades: 0 2026-W06 | installs: 0 | removals: 0 | upgrades: 0 2026-W05 | installs: 0 | removals: 0 | upgrades: 1 2026-W05 | installs: 0 | removals: 0 | upgrades: 1 2026-W05 | installs: 0 | removals: 0 | upgrades: 1 2026-W04 | installs: 0 | removals: 0 | upgrades: 0 2026-W04 | installs: 0 | removals: 0 | upgrades: 0 2026-W04 | installs: 0 | removals: 0 | upgrades: 0 2026-W03 | installs: 0 | removals: 0 | upgrades: 0 2026-W03 | installs: 0 | removals: 0 | upgrades: 0 2026-W03 | installs: 0 | removals: 0 | upgrades: 0 2026-W02 | installs: 0 | removals: 0 | upgrades: 0 2026-W02 | installs: 0 | removals: 0 | upgrades: 0 2026-W02 | installs: 0 | removals: 0 | upgrades: 0 2026-W01 | installs: 1 | removals: 1 | upgrades: 0 2026-W01 | installs: 1 | removals: 1 | upgrades: 0 2026-W01 | installs: 1 | removals: 1 | upgrades: 0 2025-W52 | installs: 0 | removals: 1 | upgrades: 0 2025-W52 | installs: 0 | removals: 1 | upgrades: 0 2025-W52 | installs: 0 | removals: 1 | upgrades: 0 2025-W52 | installs: 0 | removals: 1 | upgrades: 0 2025-W51 | installs: 1 | removals: 0 | upgrades: 0 2025-W51 | installs: 1 | removals: 0 | upgrades: 0 2025-W51 | installs: 1 | removals: 0 | upgrades: 0 2025-W50 | installs: 0 | removals: 0 | upgrades: 0 2025-W50 | installs: 0 | removals: 0 | upgrades: 0 2025-W50 | installs: 0 | removals: 0 | upgrades: 0 2025-W49 | installs: 0 | removals: 0 | upgrades: 0 2025-W49 | installs: 0 | removals: 0 | upgrades: 0 2025-W49 | installs: 0 | removals: 0 | upgrades: 0 2025-W48 | installs: 0 | removals: 0 | upgrades: 0 2025-W48 | installs: 0 | removals: 0 | upgrades: 0 2025-W48 | installs: 0 | removals: 0 | upgrades: 0 2025-W47 | installs: 0 | removals: 0 | upgrades: 6 2025-W47 | installs: 0 | removals: 0 | upgrades: 6 2025-W47 | installs: 0 | removals: 0 | upgrades: 6 2025-W46 | installs: 0 | removals: 0 | upgrades: 0 2025-W46 | installs: 0 | removals: 0 | upgrades: 0 2025-W46 | installs: 0 | removals: 0 | upgrades: 0 2025-W45 | installs: 0 | removals: 0 | upgrades: 0 2025-W45 | installs: 0 | removals: 0 | upgrades: 0 2025-W45 | installs: 0 | removals: 0 | upgrades: 0 2025-W44 | installs: 1 | removals: 0 | upgrades: 0 2025-W44 | installs: 1 | removals: 0 | upgrades: 0 2025-W44 | installs: 1 | removals: 0 | upgrades: 0 2025-W43 | installs: 2 | removals: 0 | upgrades: 0 2025-W43 | installs: 2 | removals: 0 | upgrades: 0 2025-W43 | installs: 2 | removals: 0 | upgrades: 0 2025-W42 | installs: 2 | removals: 0 | upgrades: 0 2025-W42 | installs: 2 | removals: 0 | upgrades: 0 2025-W42 | installs: 2 | removals: 0 | upgrades: 0 2025-W41 | installs: 1 | removals: 0 | upgrades: 0 2025-W41 | installs: 1 | removals: 0 | upgrades: 0 2025-W41 | installs: 1 | removals: 0 | upgrades: 0 2025-W40 | installs: 4 | removals: 0 | upgrades: 0 2025-W40 | installs: 4 | removals: 0 | upgrades: 0 2025-W40 | installs: 4 | removals: 0 | upgrades: 0 2025-W39 | installs: 1 | removals: 0 | upgrades: 0 2025-W39 | installs: 1 | removals: 0 | upgrades: 0 2025-W39 | installs: 1 | removals: 0 | upgrades: 0 2025-W38 | installs: 1 | removals: 0 | upgrades: 0 2025-W38 | installs: 1 | removals: 0 | upgrades: 0 2025-W38 | installs: 1 | removals: 0 | upgrades: 0 2025-W37 | installs: 0 | removals: 0 | upgrades: 0 2025-W37 | installs: 0 | removals: 0 | upgrades: 0 2025-W37 | installs: 0 | removals: 0 | upgrades: 0 2025-W36 | installs: 1 | removals: 0 | upgrades: 0 2025-W36 | installs: 1 | removals: 0 | upgrades: 0 2025-W36 | installs: 1 | removals: 0 | upgrades: 0 2025-W35 | installs: 0 | removals: 0 | upgrades: 0 2025-W35 | installs: 0 | removals: 0 | upgrades: 0 2025-W35 | installs: 0 | removals: 0 | upgrades: 0 2025-W34 | installs: 0 | removals: 0 | upgrades: 0 2025-W34 | installs: 0 | removals: 0 | upgrades: 0 2025-W34 | installs: 0 | removals: 0 | upgrades: 0 2025-W33 | installs: 0 | removals: 0 | upgrades: 0 2025-W33 | installs: 0 | removals: 0 | upgrades: 0 2025-W33 | installs: 0 | removals: 0 | upgrades: 0 024 WeeklyInstalls 048 WeeklyUpgrades 2026-W30 | upgrades: 2 1.3.2 2025-W47 | upgrades: 6 1.3.1 2025-W46 | upgrades: 0 1.3.0
Installations: recent average 0 per week, 35 in total
Installations minus removals
Upgrades

Links

Versions

1.3.2 ·
2026-07-24 09:39

More

TestManager

example

Intro

This extension for Sublime Text 4 allows listing, running, and inspecting the results of tests. It currently supports the following test frameworks:

The core architecture is language agnostic, and can work in principle with any language or framework not listed above. However, each framework generally has its own command-line interface and reporting format, which requires bespoke logic to handle. If your favorite test framework is not listed above, you can write your own runner/parser and register it with TestManager.

Installation

  1. Install the TestManager package (e.g., from Package Control).
  2. Open a Sublime Text project for which you want to run tests. A project is required, so if you don't have one already, create it.
  3. Edit your project settings ("Project > Edit Project") and define at least one test suite. See Adding a test suite for details.
  4. Run the command TestManager: List Tests. This should display an empty list.
  5. Press the d key to run test discovery. Your tests should now appear, and you are ready to go. Follow the help text at the bottom of the test list to get started.
  6. (optional) Configure custom color scheme for test statuses, for a nicer test list. See Custom test status colors.

Adding a test suite

In TestManager, a "test suite" is simply a collection of tests that are implemented with the same test framework. The tests from a given suite may come from multiple files, multiple classes, even multiple executables; this does not matter and is left up to you, as long as all tests within the suite are using the same framework. In general I would expect most people would only need to configure a single TestManager test suite.

Once the test suite is configured, you are unlikely to need to modify it again, even if you add more tests, test files, etc. TestManager implements dynamic test discovery, so you do not have to list all tests by hand; you only need to tell the plugin where to find your tests.

Test suites are added to your Sublime Text project settings in the following way:

{
    "settings":
    {
        "TestManager":
        {
            "test_suites": [
                {
                    "id": "suite1",
                    ...
                },
                {
                    "id": "suite2",
                    ...
                },
                ...
            ]
        }
    }
}

Inside the "test_suites" array, you can list as many test suites as you need. The format of each entry is:

The rest of the fields are specific to the chosen test framework, however there are a number of fields that are currently common to all test frameworks:

The following sections describe fields that are only available in specific test frameworks.

Catch2 / Doctest / GoogleTest

The following field can also be set:

Pytest

The following field can also be set:

    "python": ["conda", "run", "--no-capture-output", "-n", "my-environment", "python"]

Cargo

The following field can also be set:

PHPUnit

The following field can also be set:

Internal data model

The content of this section is not necessary for using TestManager. It is for developers only, or those who wish to implement their own custom framework.

The data model is a tree-like structure, where each element is a TestItem. All tests are leaves of this tree (no children). Nodes of the tree correspond to groups of any kind: it could be a test class (fixture), a file, a folder, ... A node contains one or more child; each child can itself be another sub-group, or it can be a test. The data model makes no assumption about the meaning of this grouping structure, so each framework can specify only the grouping level it needs. For example, if the test framework has no concept of "test class", then that grouping level does not need to exist in the tree.

Each test is described by the following fields:

NB: The above describes the data model in Python. When the test data is stored on disk, it is stored in an SQLite database, and each test is then a row in a table. Nodes of the tree are not stored on disk, because they do not contain any new information (their content is entirely derived from that of their respective children).

Register new framework

To add a new test framework, you must create a new class that implements the TestFramework interface (see abstract base class definition in test_framework.py).

from TestManager.test_framework import TestFramework

class YourTestFramework(TestFramework):
    def __init__(self, suite: TestSuite):
        """
        Initialise any state and settings you need.
        Note: The instance is not long-lived: it is created for the duration of the test discovery
        or test run, and destroyed afterwards. Any persistent state, e.g., the list and status of
        tests, should be stored in the TestData class.
        """
        super().__init__(suite)

    def discover(self) -> List[DiscoveredTest]:
        """
        Must run test discovery and return a list of discovered tests. The discovered tests will
        be registered with the TestData class automatically, you do not need to do this yourself.
        """
        return []

    def run(self, grouped_tests: Dict[str, List[str]]) -> None:
        """
        Must run the tests selected in `grouped_tests`.
        The tests are grouped by "executable" (as defined during test discovery), for efficiency.
        While tests are running, it is expected that this function will notify the TestData
        class of any of the following events:
         - TestData.notify_test_started()
         - TestData.notify_test_output()
         - TestData.notify_test_finished()
        """
        pass

You must then call somewhere:

register_framework("name-of-your-framework",
                   your_framework_factory_function,
                   your_framework_default_settings)

... where your_framework_default_settings is a dictionary holding the default settings for your new framework, and your_framework_factory_function is a function that creates an instance of your framework class, constructed from settings in the user-supplied JSON data (see Adding a test framework). The signature of the factory function must be:

def your_framework_factory_function(suite: TestSuite, settings: Dict) -> YourTestFramework:
    # Extract useful parameters from settings and forward them to your class.
    return YourTestFramework(suite)

The builtin framework class for Google Test is a good example to emulate, and has one of the simplest parser. See test_frameworks/gtest.py.

You can then either publish this framework as a separate Sublime Text plugin, or offer to contribute it to this repository to make it available by default.

Custom test status colors

By default, the test list does not use different colors to display passed/failed/skipped tests, it only shows a different symbol. Using different colors can make it easier to read, and is recommended. Unfortunately this is difficult to do out-of-the-box for TestManager; the right colors to use will depend on your favorite color scheme (dark vs light, etc.).

To set up custom colors, go to "Preferences > Customize Color Scheme", and enter the following. Feel free to then edit the chosen colors to your liking.

{
    "variables":
    {
    },
    "globals":
    {
    },
    "rules":
    [
        {
            "name": "TestManager failed (icon)",
            "scope": "string.other.test-list.status-marker.failed",
            "foreground": "#e9677e"
        },
        {
            "name": "TestManager failed (stats)",
            "scope": "comment.other.test-list.tests.failed.some",
            "foreground": "#e9677e"
        },
        {
            "name": "TestManager crashed (icon)",
            "scope": "string.other.test-list.status-marker.crashed",
            "foreground": "#e9677e"
        },
        {
            "name": "TestManager crashed (stats)",
            "scope": "comment.other.test-list.tests.crashed.some",
            "foreground": "#e9677e"
        },
        {
            "name": "TestManager stopped (icon)",
            "scope": "string.other.test-list.status-marker.stopped",
            "foreground": "#97d1ed"
        },
        {
            "name": "TestManager stopped (stats)",
            "scope": "comment.other.test-list.tests.stopped.some",
            "foreground": "#97d1ed"
        },
        {
            "name": "TestManager passed (icon)",
            "scope": "string.other.test-list.status-marker.passed",
            "foreground": "#7efbac"
        },
        {
            "name": "TestManager passed (stats)",
            "scope": "comment.other.test-list.tests.passed.some",
            "foreground": "#7efbac"
        },
        {
            "name": "TestManager skipped (icon)",
            "scope": "string.other.test-list.status-marker.skipped",
            "foreground": "#f0ce7b"
        },
        {
            "name": "TestManager skipped (stats)",
            "scope": "comment.other.test-list.tests.skipped.some",
            "foreground": "#f0ce7b"
        },
        {
            "name": "TestManager not-run (icon)",
            "scope": "string.other.test-list.status-marker.not-run",
            "foreground": "#97d1ed"
        },
        {
            "name": "TestManager not-run (stats)",
            "scope": "comment.other.test-list.tests.not-run.some",
            "foreground": "#97d1ed"
        },
        {
            "name": "TestManager running (icon)",
            "scope": "string.other.test-list.status-marker.running",
            "foreground": "#c582c3"
        },
    ]
}

Results

Packages