Skip to main content

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 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.

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:

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. 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()

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.

#include "test_fiff_rwr.moc"

Naming Conventions

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

ObjectRule
Project nametest_something_meaningful
Class nameTestSomethingMeaningful