# Testing
It is highly recommended to write tests for your custom checks.

## Rego testing
To help you verify the correctness of your custom checks, OPA gives you a framework that you can use to write tests for your checks. 
By writing tests for your custom checks you can speed up the development process of new rules and reduce the amount of time it takes to modify rules as requirements evolve.

For more details, see [Policy Testing][opa-testing].

!!! example
    ```
    package user.dockerfile.ID002

    test_add_denied {
        r := deny with input as {"stages": {"alpine:3.13": [
            {"Cmd": "add", "Value": ["/target/resources.tar.gz", "resources.jar"]},
            {"Cmd": "add", "Value": ["/target/app.jar", "app.jar"]},
        ]}}

        count(r) == 1
        r[_] == "Consider using 'COPY /target/app.jar app.jar' command instead of 'ADD /target/app.jar app.jar'"
    }
    ```

To write tests for custom checks, you can refer to existing tests under [trivy-checks][trivy-checks].

## Go testing
[Fanal][fanal] which is a core library of Trivy can be imported as a Go library.
You can scan config files in Go and test your custom checks using Go's testing methods, such as [table-driven tests][table].
This allows you to use the actual configuration file as input, making it easy to prepare test data and ensure that your custom checks work in practice.

In particular, Dockerfile and HCL need to be converted to structural data as input, which may be different from the expected input format.

!!! tip
    We recommend writing OPA and Go tests both since they have different roles, like unit tests and integration tests.

The following example stores allowed and denied configuration files in a directory.
`Successes` contains the result of successes, and `Failures` contains the result of failures.

``` go
{
	name:  "disallowed ports",
	input: "configs/",
	fields: fields{
		policyPaths: []string{"policy"},
		dataPaths:   []string{"data"},
		namespaces:  []string{"user"},
	},
	want: []types.Misconfiguration{
		{
			FileType: types.Dockerfile,
			FilePath: "Dockerfile.allowed",
			Successes: types.MisconfResults{
				{
					Namespace: "user.dockerfile.ID002",
					PolicyMetadata: types.PolicyMetadata{
						ID:          "ID002",
						Type:        "Docker Custom Check",
						Title:       "Disallowed ports exposed",
						Severity:    "HIGH",
					},
				},
			},
		},
		{
			FileType: types.Dockerfile,
			FilePath: "Dockerfile.denied",
			Failures: types.MisconfResults{
				{
					Namespace: "user.dockerfile.ID002",
					Message:   "Port 23 should not be exposed",
					PolicyMetadata: types.PolicyMetadata{
						ID:          "ID002",
						Type:        "Docker Custom Check",
						Title:       "Disallowed ports exposed",
						Severity:    "HIGH",
					},
				},
			},
		},
	},
},
```

`Dockerfile.allowed` has one successful result in `Successes`, while `Dockerfile.denied` has one failure result in `Failures`.

[opa-testing]: https://www.openpolicyagent.org/docs/latest/policy-testing/
[defsec]: https://github.com/aquasecurity/trivy-checks/tree/main
[table]: https://go.dev/wiki/TableDrivenTests
[fanal]: https://github.com/aquasecurity/fanal