Running automated tests
This page describes how to run the midas tests: the full test suite (with make test, or step by step with CMake and CTest), the older Python unit tests, and the test programs installed in bin.
For more details, see tests/README.md in the midas repository, and the README.md and testplan.md in each directory under tests.
There are three sets of tests:
| Tests | What they test | How to run them |
|---|---|---|
| The test suite | The C++ libraries and programs (GoogleTest), the Python package (pytest), and the JavaScript of the web pages (node:test and Playwright) | make test from the midas directory, or step by step with CMake and ctest. Not built by default |
| Python unit tests | The Python package, in python/tests |
python3 -m unittest, against a running experiment |
| Test programs | The ODB, the frontend frameworks and the operating system functions | Run the programs in bin by hand |
The test suite
The test suite is in the tests directory. It runs each test in its own temporary experiment, so it doesn't touch your experiments, and it doesn't need a running midas.
Note
Before September 2026, make test ran a short self test instead. It created an experiment in testexpt, ran a frontend and mlogger through a few runs, and compared the output with testexpt.example. make test now runs the full test suite.
Requirements
You need these system packages:
- a C++ compiler,
make, CMake 3.24 or newer andgit - Python 3 and
pip - Node.js 22 or newer and
npm. Linux distributions often have an older version, so install it from NodeSource if needed lcov, only for coverage reports
For example, on Debian or Ubuntu:
sudo apt install build-essential cmake git python3 python3-pip lcov
curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash -
sudo apt install nodejs
On macOS with Homebrew:
xcode-select --install
brew install cmake git python node lcov
The tests also need about 32 MB of shared memory (/dev/shm on Linux). This matters in Docker containers, which have only 64 MB by default.
The first build of the tests downloads GoogleTest (unless it is already installed), so it needs network access once. A normal midas build doesn't build the tests, and doesn't need network access.
Running everything with make test
From the midas directory:
cd $MIDASSYS
make test
make test has three steps, which you can also run one at a time:
| Step | What it does |
|---|---|
make test-deps |
Checks that Node.js is new enough. Installs the midas Python package (pip install -e python/), pytest and pytest-cov, the JavaScript test packages (npm install in tests/resources) and Playwright's Chromium browser |
make test-build |
Configures build with -DMIDAS_BUILD_TESTS=ON, builds midas and the tests, and installs midas into the midas directory (bin, lib, ...) |
make test-run |
Runs all the tests with ctest --test-dir build --output-on-failure |
Warning
make test-deps installs Python packages into whichever Python environment is active, so you may want to activate a virtual environment first. make test-build installs the newly built midas programs and libraries into the midas directory, replacing the ones there. Don't run it in a midas installation that a running experiment is using.
Building the tests by hand
The tests are built by the normal midas CMake build when MIDAS_BUILD_TESTS is on:
cd $MIDASSYS
mkdir build
cd build
cmake .. -DMIDAS_BUILD_TESTS=ON
make
make install
make install is needed for the tests that run midas programs (e.g. mhttpd) or use the midas library from Python, as they use the installed copies in the midas directory. Install the Python and JavaScript test packages first (e.g. with make test-deps), as their tests are only registered with CTest if pytest and tests/resources/node_modules exist when CMake runs. Tests whose prerequisites are missing are skipped rather than failing.
Running the tests with ctest
ctest runs all the tests. Each C++ test case is a separate CTest entry, while the Python and JavaScript tests are run in a few larger entries. Run it from the midas directory:
export MIDASSYS=$PWD
ctest --test-dir build --output-on-failure
Useful options:
| Option | Effect |
|---|---|
-j8 |
Runs 8 tests at a time. This is several times faster. Each test uses shared memory, so in a container with little shared memory, use fewer jobs or none |
-N |
Lists the tests without running them |
-R <regex> |
Runs only the tests whose names match, e.g. -R '^OdbXx' |
-LE External |
Leaves out the end-to-end browser tests |
-LE LiveHttp |
Leaves out the tests that start a real mhttpd (about 25 tests, which take about 26 s) |
-LE Pipeline |
Leaves out the end-to-end test that runs several midas programs together |
Some tests fail on purpose: they check for the correct behaviour where midas still has a known bug. They are listed in tests/expected_failures.txt, and CTest counts them as passing while they fail. So ctest reports no failures on an unmodified midas, and anything that fails is a new problem. If a bug is fixed, its test starts passing and CTest reports it as failed, as a reminder to remove it from expected_failures.txt. The bugs themselves are described in tests/BUG_SUMMARY.md.
Running one suite
C++
Each C++ suite is built into one program, which you can run directly. This gives more detailed GoogleTest output, and --gtest_filter selects tests by name:
./build/tests/src/midas_unit_tests --gtest_filter='OdbXxValues.*'
./build/tests/src/midas_unit_tests --gtest_list_tests
| Directory | Program | Tests |
|---|---|---|
tests/src |
midas_unit_tests |
The midas library (src) |
tests/progs |
midas_progs_unit_tests |
The midas programs (progs), including tests that run several programs together |
tests/midasio |
midasio_unit_tests |
midasio (reading and writing midas files) |
tests/mjson |
mjson_unit_tests |
mjson |
tests/mvodb |
mvodb_unit_tests |
MVOdb |
tests/mxml |
mxml_unit_tests |
mxml |
tests/msetpoint |
msetpoint_unit_tests |
The MSetPoint EPICS frontend |
tests/manalyzer |
manalyzer_unit_tests |
manalyzer |
tests/mscb |
mscb_unit_tests |
MSCB |
The programs are in the same directories under build. Tests that use an ODB need MIDASSYS to be set, as they run $MIDASSYS/bin/odbinit to create their temporary experiment. To add a test, add a test_*.cxx file to the suite's directory: it is found automatically.
Python
The Python tests are in tests/python, and are run with pytest. They are divided into tiers with pytest markers. The tests that need no midas installation run with:
pip install -e python/
pytest tests/python -m "not needs_midas"
The tests that use the midas library need a built midas, and create their own temporary experiment:
export MIDASSYS=$PWD
export PYTHONPATH=$PWD/python
pytest tests/python -m "needs_midas and not external"
Tests marked external need hardware or a network service, and are left out unless you select them with -m external. In CTest, the two tiers are the python_pure and python_live entries. See tests/python/README.md for the markers and fixtures.
JavaScript
The JavaScript tests are in tests/resources. The unit tests load the JavaScript files of the web pages into a simulated browser (jsdom), and the end-to-end tests run a real mhttpd and drive the Chromium browser with Playwright:
cd tests/resources
npm install
npm run test:unit
npx playwright install chromium
npm run test:e2e
package.json also has scripts that run the unit tests of one file, e.g. npm run test:unit:mplot. In CTest, the two tiers are the js_unit and js_e2e entries. See tests/resources/README.md for details.
Coverage
make coverage builds midas with coverage instrumentation, runs all the tests, and writes a coverage report for each language:
| Report | Language |
|---|---|
cov_html |
C++ (with lcov) |
cov_html_python |
Python (with pytest-cov) |
tests/resources/coverage |
JavaScript |
make coverage-recapture measures the coverage again with the existing build, without configuring it again. It doesn't rebuild either, so run make and make install in build first. Some code is deliberately left out of the coverage figures, e.g. obsolete functions. See tests/coverage_exclusions.md for the list and the reasons.
Continuous integration
The GitLab CI job build_and_test (in .gitlab-ci.yml) runs the test suite on Ubuntu 24.04, with ROOT installed. It runs make test-deps and make test-build as root, then make test-run as an unprivileged user, because some tests check what happens when a file can't be read. The job doesn't run on every commit. It runs on a schedule, or when started by hand from the GitLab web interface with the variable JOB_NAME set to full-test. If it fails, the CTest log and the Playwright reports are kept as job artifacts for a week.
Python unit tests
The original unit tests of the Python package are in python/tests, and use the Python unittest framework. Many of them have since been moved into the test suite (tests/python), which runs them in a temporary experiment.
Warning
These tests connect to the current experiment (as set by MIDAS_EXPT_NAME or exptab). They start and stop runs, and change the ODB. Only run them in a test experiment.
With the environment set up for a test experiment:
cd $MIDASSYS/python/tests
python3 -m unittest # all the tests
python3 -m unittest test_odb # the tests in test_odb.py
python3 -m unittest test_odb.TestOdb.testInt # one test
Test programs
midas also builds some programs that test parts of midas by hand, such as test_odb, test_mvodb and torture_odb for the ODB, hwtest for the hardware and operating system, and the fetest frontend. They are installed in bin. Some of them (e.g. test_mvodb and torture_odb) don't report failures through their exit code, so check their output. See Test programs for the list.