Write test rules alongside the policy, run the opa test command, and check coverage before a rule can block anyone. Each test feeds sample input to the policy and asserts the result. A policy with no tests is a guess that happens to run in your pipeline.
Why test policies
A policy that wrongly blocks stops teams from shipping. One that wrongly allows gives false comfort. Both are bugs, and both are cheap to catch with a few examples. Testing also makes a policy safe to change later, which matters when many repositories depend on it.
How Open Policy Agent tests work
According to the OPA documentation, tests are standard Rego rules whose names start with test_. It is good practice, though not required, to put tests in a package whose name ends in test. The opa test command discovers and runs every rule with the test prefix in the files or directories you pass it, loading directories recursively.
The docs show the output as a list of passes and failures, with a summary count. The verbose flag prints each test name and result.
OPA can also report coverage: which lines of the policy were evaluated and which were not. The docs explain that an uncovered rule head means the rule body was never true, and an uncovered expression means it was never evaluated.
A worked example
Suppose a policy denies a deployment that does not set runAsNonRoot. The policy is similar to the example in the Conftest documentation.
package main
deny contains msg if {
input.kind == "Deployment"
not input.spec.template.spec.securityContext.runAsNonRoot
msg := "Containers must not run as root"
}
Now the tests. One checks that a bad input is denied, and one checks that a good input passes.
package main_test
import data.main
test_root_deployment_denied if {
count(main.deny) > 0 with input as {
"kind": "Deployment",
"spec": {"template": {"spec": {"securityContext": {}}}}
}
}
test_non_root_deployment_allowed if {
count(main.deny) == 0 with input as {
"kind": "Deployment",
"spec": {"template": {"spec": {"securityContext": {"runAsNonRoot": true}}}}
}
}
Run them from the policy directory with the opa test command and its verbose flag. Syntax varies a little between OPA versions, so check the documentation for the version you run.
What to test
- A clear failure. Input that must be blocked.
- A clear pass. Input that must be allowed.
- Edge cases. Missing fields, empty lists and unexpected kinds. Policies often break on absent data.
- Past incidents. Every time a policy gets something wrong, add a test for it.
Make tests part of the road
Run the policy tests in the pipeline of the policy repository, and publish a new version once they pass. Then roll the policy out in warn mode before you enforce it, as covered in policy as code for CI/CD without breaking builds.
Where Safeguard fits
Safeguard's policies and gates can be set to report before they block, which complements unit tests with a real world trial on your own repositories. You can try a free scan at gold.safeguard.sh/scan.
Quick check
Do I need 100 percent coverage?
No, but read the uncovered lines. Each one is either dead logic or a case you have not tried.
Can I test policies without a cluster or pipeline?
Yes. The tests run locally on sample input, with no cluster, which is why they are quick to run on every change.
Sources
Last reviewed: 19 October 2026.