---
title: Writing a Unit Test
sidebar_label: Writing a Unit Test
---

# Writing a Unit Test

MNE-CPP requires unit tests for all new functionality. The focus is on functional testing rather than 100% code coverage. Writing tests helps you fully understand what your code does and ensures the CI pipeline catches regressions early — a failing test is the first indicator that a change broke something.

## What and How to Test

Every new function should be tested. Consider the use case, determine how to validate the output, and — where possible — compare results against a reference implementation (e.g., MNE-Python, MNE-C, or MNE-Matlab). Once you have reference results, proceed with the steps below.

## Creating a new Test

A good starting point is to look at existing tests under `src/testframes/`. You can duplicate an existing test directory (e.g., `test_fiff_rwr`) and adapt it for your new test. Make sure to:

1. Rename the directory and source files to match your test name.
2. Update the `CMakeLists.txt` inside the new test directory.
3. Register the new test in the parent `src/testframes/CMakeLists.txt` via `add_subdirectory()`.

## Structuring the Test

Always keep our [Coding Conventions](contr-style.mdx) in mind. Consider taking a look at already available tests to get started. First, you create a class named after your test: `TestName`. The following code snippet shows an example for a test. The `slots` define the functions to execute your test logic in `initTestCase()` and compare the output to reference values, e.g., `compareValue()`. You can also declare threshold values as private variables that indicate the maximum allowed difference when comparing. An example can be found [here](https://github.com/mne-tools/mne-cpp/blob/main/testframes/test_fiff_rwr/test_fiff_rwr.cpp).

```cpp
class TestFiffRWR: public QObject
{
    Q_OBJECT

public:
    TestFiffRWR();

private slots:
    void initTestCase();
    void compareValue();
    void cleanupTestCase();

private:
    // some variables and error thresholds
    double dEpsilon;
    Eigen::MatrixXd mFirstInData;
    Eigen::MatrixXd mSecondInData;
};
```

### initTestCase()

Here you execute and declare everything that is necessary for setting up your test. You generate and load all values in a variable that can be compared to later. If you want to load external calculated data in e.g. `.txt` files you can use:

```cpp
Eigen::MatrixXd mDataFromFile;
UTILSLIB::IOUtils::read_eigen_matrix(mDataFromFile, QCoreApplication::applicationDirPath() + "../resources/data/mne-cpp-test-data/Result/<yourFile>.txt");
```

All files you use, have to be added to [mne-cpp-test-data](https://github.com/mne-tools/mne-cpp-test-data). In case you need to add new data open a Pull Request to this repository. The files you use should be as small as possible. If you need a .fif file, have a look at the already existing data first.

### compareValue()

```cpp
void TestFiffRWR::compareValue()
{
    // compare your data here, think about usefull metrics
    Eigen::MatrixXd mDataDiff = mFirstInData - mSecondInData;
    QVERIFY( mDataDiff.sum() < dEpsilon );
}
```

Here you compare the output of your function to the reference data. `QVERIFY` performs the assertion. Choose meaningful metrics and thresholds for your comparison. Use a separate compare function for each value you test — don't combine unrelated comparisons.

### Possible Error Message

It might be possible that the last line of the test shows an error in your editor. Don't worry about this, once you have built the test project, the error will disappear.

```cpp
#include "test_fiff_rwr.moc"
```

### Naming Conventions

Please follow the following naming conventions when naming your test project and class:

|Object|Rule|
| --------------- | ------------------- |
| Project name 	  |`test_something_meaningful`|
| Class name 	  |`TestSomethingMeaningful`  |
