Tests
ontopoiesis test runs Cypher-based structural assertions against a built .lbug
projection. Use it to enforce structural constraints that should hold on every version of
the ontology — labeling coverage, deprecation hygiene, declared domains and ranges. These
checks integrate naturally into CI.
All queries run against the standard projection shape: construct nodes in N, semantic
reference edges in E, construct kind in n.kind.
File Organization¶
Test files are collected from a directory you pass to ontopoiesis test. Keep project-specific
tests in a tests/ directory alongside the ontology sources. Build the projection with
ontopoiesis build before running tests. The runner accepts either a directory (all matching
.cypher files are collected) or a single .cypher file.
Error-level tests¶
Each error-level assertion lives in a test_*.cypher or *_test.cypher file. The
runner executes each query against the projection and fails the test if any rows are
returned. Violations are rows; an empty result is a pass. A single error-level failure
causes a non-zero exit code.
For this example, the rule prohibits negative object property assertions in the published
ontology. The example intentionally fails — the sample data contains one negative
hasDaughter assertion, from Bill to Susan.
// Example project policy: negative object property assertions are not allowed.
MATCH (ax:N {kind: 'NegativeObjectPropertyAssertion'})
-[:E {role: 'subject'}]->(source:N)
MATCH (ax)-[:E {role: 'property'}]->(prop:N)
MATCH (ax)-[:E {role: 'object'}]->(target:N)
RETURN
source.iri AS source,
prop.iri AS property,
target.iri AS target
ORDER BY source.iri, prop.iri, target.iri
Store the query at tests/test_negative_property_assertions.cypher, build the
projection once, and run:
ontopoiesis build family.owlxml -o family.lbug
ontopoiesis test family.lbug tests/test_negative_property_assertions.cypher
Because family.owlxml contains one negative hasDaughter assertion, the test returns
a violation and exits non-zero:
=========================== short test summary info ============================
FAILED tests/test_negative_property_assertions.cypher::test_negative_property_assertions.cypher
============================== 1 failed in 1.00s ===============================
If you want this example to pass instead, remove the negative property assertion or change the query to ignore it. A test that finds no violations prints:
Warning-level tests¶
A warn_*.cypher or *_warn.cypher file works identically to an error-level test
except that violations do not fail the run. Violations appear in a dedicated
terminal summary section; the exit code remains zero. Use warning-level tests
for quality signals you want to track without blocking CI.
For example, self-referential object-property definitions may deserve review without
being outright errors. The Primer sample contains NarcisticPerson, defined with an
ObjectHasSelf restriction over loves:
MATCH (ax:N {kind: 'EquivalentClasses'})
-[:E {role: 'operand'}]->(named_class:N {kind: 'Class'}),
(ax)-[:E {role: 'operand'}]->(:N {kind: 'ObjectHasSelf'})
RETURN named_class.iri AS class
ORDER BY class
NarcisticPerson matches the warning query, so the warning appears in the
Cypher warning summary, but the exit code remains zero:
============================= cypher warnings =============================
WARN warn_self_referential_definitions.cypher
query returned 1 violation row(s)
... run with -v to see a sample
Pass -v to see a sample of the violation rows:
CI Integration¶
The common CI pattern is:
- build the projection once
- run
ontopoiesis lintas the shared baseline gate - run
ontopoiesis testfor project-specific assertions
Example:
uv run ontopoiesis build ontology.owlxml -o ontology.lbug
uv run ontopoiesis lint ontology.lbug
uv run ontopoiesis test ontology.lbug tests/
ontopoiesis test forwards extra pytest flags, so -v, -vv, and -x can be passed
through when you want more detail or fail-fast behaviour during local debugging or CI:
uv run ontopoiesis test ontology.lbug tests/ -v
uv run ontopoiesis test ontology.lbug tests/ -vv
uv run ontopoiesis test ontology.lbug tests/ -x
For a full GitHub Actions example and gate/advisory split, see CI.
Troubleshooting¶
No test files collected. The runner requires files named test_*.cypher,
*_test.cypher, warn_*.cypher, or *_warn.cypher. Files with other names are
silently ignored. Confirm the file names match one of these conventions.
The test fails even though the query returns no rows when run manually. The runner
and ontopoiesis query use the same projection file but different sessions. If the
projection file was modified between the two commands, results may differ. Rebuild the
projection and re-run both commands against the fresh file.
Warning-level violations appear but the exit code is non-zero. Warning-level
files (warn_*.cypher) never cause a non-zero exit on their own. If the exit
code is non-zero, at least one error-level test file returned violations or
pytest encountered a separate usage/collection failure. Check the short test
summary for FAILED entries.
Related¶
ontopoiesis lint runs the same test runner against the built-in baseline rules rather than
your own .cypher files. If you want structural quality checks without writing your own
queries, start there. See the Lint guide for running lint and the
lint rule reference for the full catalogue and
selection options.