A lightweight automated testing framework for command-line applications. Define test cases in JSON/YAML, run all validations with a single command.
Particularly suited for scientific computing — deep HDF5 support with regex table matching, data filtering, and tolerance-based comparison, making simulation result verification effortless.
This project was created from a real need: regression testing finite-element software.
In solver-style projects, checking the exit code is not enough. A test often needs to run multiple commands, generate numerical result files, compare HDF5/CSV outputs with tolerances, and make sure old cases do not become slower over time.
CLI Test Framework was built for that workflow.
- Golden File Assertion —
compare_filesembedded in testexpected, compares output files against baselines with tolerance - Parallel Execution — Multi-thread / multi-process, 3-5x speedup
- Resource-Aware Scheduling — Automatic CPU core management, prevents solver thread runaway
- Sequence Steps — Multi-step execution within a single test case, fail-fast
- Setup Module — Auto-configure environment variables before tests, auto-cleanup after
- File Comparison — Text / JSON / CSV / XML / HDF5 / Binary, with CLI and embedded assertion support
- Filtered Execution — Run specific test cases by name
- JUnit XML Output —
--junit-xmlfor GitLab CI / Jenkins / CircleCI test report panels
pip install cli-test-framework- Create
test_cases.json:
{
"test_cases": [
{
"name": "hello",
"command": "echo",
"args": ["Hello World"],
"expected": {
"return_code": 0,
"output_contains": ["Hello World"]
}
}
]
}- Run:
cli-test run test_cases.jsonRun a simulation, then compare its output file against a reference:
{
"test_cases": [
{
"name": "FEA displacement check",
"command": "my_solver",
"args": ["--input", "case1.dat", "--output", "out.h5"],
"expected": {
"return_code": 0,
"compare_files": [
{
"actual": "out.h5",
"baseline": "ref/golden.h5",
"rtol": 1e-5,
"atol": 1e-8,
"tables": ["NASTRAN/RESULT/NODAL/DISPLACEMENT"]
}
]
}
}
]
}actual– file produced by the commandbaseline– reference file to compare againsttype– comparator type (auto-detected from extension if omitted:.h5→h5,.json→json,.csv→csv,.xml→xml,.txt→text)- all other keys are forwarded as comparator parameters (
rtol,atol,tables,table_regex,data_filter,encoding,structure_only,delimiter,compare_mode,key_field, etc.)
Multiple files and mixed assertion types coexist naturally:
{
"expected": {
"return_code": 0,
"output_contains": ["simulation finished"],
"compare_files": [
{"actual": "out.h5", "baseline": "ref/disp.h5", "rtol": 1e-5},
{"actual": "report.csv", "baseline": "ref/expected.csv", "rtol": 1e-6}
]
}
}cli-test run test_cases.json --parallel --workers 4cli-test run test_cases.json --junit-xml report.xmlIn GitLab CI:
# .gitlab-ci.yml
artifacts:
reports:
junit: report.xmlfrom cli_test_framework.runners import JSONRunner, ParallelJSONRunner
# Sequential
runner = JSONRunner(config_file="test_cases.json")
success = runner.run_tests()
# Parallel
runner = ParallelJSONRunner(config_file="test_cases.json", max_workers=4, execution_mode="thread")
success = runner.run_tests()compare-files result1.h5 result2.h5 --h5-table-regex "output_.*" --h5-rtol 1e-5📖 Full Documentation: docs/user_manual.md
- JUnit XML output: New
--junit-xml <filepath>CLI option writes JUnit-format XML reports that integrate directly with GitLab CI, Jenkins, CircleCI, and other CI tools. Supportspassed/failed/timeout/errorstatus mapping. Zero extra dependencies — built withxml.etree.ElementTree.
- Unified logging system: All diagnostic output (executor, runner, scheduler, setup) now uses Python's standard
loggingmodule under thecli_test_frameworknamespace. Library users can suppress output entirely vialogging.getLogger("cli_test_framework").setLevel(logging.WARNING). Removes the previous ad-hocprint()+_print_lockpattern —loggingis inherently thread-safe. - Default handler: A
StreamHandlerat INFO level is installed on first import, so CLI behavior is unchanged. Use--verbose/--debugto enable DEBUG-level output. - Public API:
get_logger(name)exposed viacli_test_framework.get_loggerfor consistent logger creation in extensions.
- Golden file assertion:
compare_filesis now a first-class assertion in testexpected— compare output files against baselines directly in your test definitions, with full tolerance and parameter support. Thefile_comparatorsubsystem is now integrated into the assertion pipeline, completing the closed loop from command execution to result verification.
- Runtime history tracking (
--history-dir): persist per-case execution time in.symtest, enable smart scheduling & regression detection - Regression warning: alert when a case runs slower than historical average × threshold (
--regression-threshold, default 1.5) - Smart scheduling: parallel runner prioritizes historical
avg_durationover configestimated_timefor task ordering - Per-case duration now shown in test result output
- Run specific test cases by name (
-t/test_case_filter)
- Steps feature: sequential multi-command execution within a single test case, fail-fast
- Resource-aware scheduling: auto-detect CPU cores, semaphore-based core allocation
- Auto-inject
OMP_NUM_THREADS/MKL_NUM_THREADS/NPROCto prevent solver thread runaway - Per-test
timeoutsupport to prevent hanging
- Multi-thread / multi-process parallel execution, 3-5x speedup
Before submitting a PR, please make sure all tests pass:
python tests\run_all.pyMIT