Unit tests¶
KnitPkg encourages the use of unit tests to validate packages.
Unit tests are small, repeatable checks that verify specific behaviors of your package code. They help you catch regressions early, and—when well named—act as executable documentation for how your public API is supposed to behave.
This is especially valuable for packages because packages are meant to be reused as dependencies: when you publish a new package version, you want confidence that core behaviors still work as expected.
Where unit tests live¶
Unit tests should be placed under the project directory:
tests/
And they must be listed in your manifest under compile: so they get compiled automatically:
How KnitPkg unit tests work in practice¶
In practice, a KnitPkg unit test is a MetaTrader Script (.mq5):
- Compile the test script (for example using
kp compile). - Run the compiled script inside MetaTrader by attaching it to a chart.
- Read the results in the MetaTrader console output (the Experts tab) to see which tests passed or failed.
This approach is intentionally simple: it relies on MQL + printing to the Experts log.
Current state of test support
Unit tests in KnitPkg do not yet have rich “test runner” features such as automatic discovery, structured reports, or IDE integration. Better support is planned, but today the workflow is manual and lightweight.
Test skeleton generated by kp init¶
The command kp init can generate a basic test scaffold. Below is an example of how a unit test script can be structured:
The three key parts are highlighted:
- Code under test (line 20): include the header under test with the standard MQL #include directive.
- Test function (lines 25–30): a
boolfunction that returnstruefor pass,falsefor fail. - Test invocation (lines 38–47): the code that calls the test, updates counters, and prints the result.
Each new test you add must follow the same pattern: define a new bool test function, then add a corresponding call inside DoTests(...).
How to write good unit tests for packages¶
Even with a simple harness, you can write effective tests by following a few principles:
-
Test behavior, not implementation details Focus on public functions/types and observable results. This keeps tests more stable when you refactor.
-
Keep tests readable A common structure is “Arrange, Act, Assert” (AAA): set up inputs, call the code, verify the outcome.
-
Name tests as executable documentation Prefer descriptive names that express: what is tested, under which scenario, and what is expected.
-
Prefer small, focused tests When a test is trying to prove too many things at once, failures become harder to interpret and maintenance gets unpleasant.
Real examples¶
Examples of unit tests in the bar package:
Example of unit tests in the calc package:
About current repository layouts
In calc and bar, unit tests currently live under src/, but this is considered a mistake.
In a future version, those tests will be moved to tests/ to match the recommended layout described in this document.