diff --git a/cmd/cli/kubectl-kyverno/apis/v1alpha1/test.go b/cmd/cli/kubectl-kyverno/apis/v1alpha1/test.go
index 19f9e1e059..4595a01431 100644
--- a/cmd/cli/kubectl-kyverno/apis/v1alpha1/test.go
+++ b/cmd/cli/kubectl-kyverno/apis/v1alpha1/test.go
@@ -1,6 +1,7 @@
 package v1alpha1
 
 import (
+	"github.com/kyverno/kyverno-json/pkg/apis/v1alpha1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
@@ -32,6 +33,31 @@ type Test struct {
 	// Results are the results to be checked in the test
 	Results []TestResult `json:"results,omitempty"`
 
+	// Checks are the verifications to be checked in the test
+	Checks []CheckResult `json:"checks,omitempty"`
+
 	// Values are the values to be used in the test
 	Values *ValuesSpec `json:"values,omitempty"`
 }
+
+type CheckResult struct {
+	// Match tells how to match relevant rule responses
+	Match CheckMatch `json:"match,omitempty"`
+
+	// Assert contains assertion to be performed on the relevant rule responses
+	Assert v1alpha1.Any `json:"assert"`
+
+	// Error contains negative assertion to be performed on the relevant rule responses
+	Error v1alpha1.Any `json:"error"`
+}
+
+type CheckMatch struct {
+	// Resource filters engine responses
+	Resource *v1alpha1.Any `json:"resource,omitempty"`
+
+	// Policy filters engine responses
+	Policy *v1alpha1.Any `json:"policy,omitempty"`
+
+	// Rule filters rule responses
+	Rule *v1alpha1.Any `json:"rule,omitempty"`
+}
diff --git a/cmd/cli/kubectl-kyverno/commands/test/command.go b/cmd/cli/kubectl-kyverno/commands/test/command.go
index 7a6f139138..1a45960539 100644
--- a/cmd/cli/kubectl-kyverno/commands/test/command.go
+++ b/cmd/cli/kubectl-kyverno/commands/test/command.go
@@ -101,7 +101,7 @@ func testCommandExecute(
 		}
 	}
 	rc := &resultCounts{}
-	var table table.Table
+	var fullTable table.Table
 	for _, test := range tests {
 		if test.Err == nil {
 			deprecations.CheckTest(out, test.Path, test.Test)
@@ -121,11 +121,24 @@ func testCommandExecute(
 				return fmt.Errorf("failed to run test (%w)", err)
 			}
 			fmt.Fprintln(out, "  Checking results ...")
-			t, err := printTestResult(out, filteredResults, responses, rc, failOnly, detailedResults, test.Fs, resourcePath)
-			if err != nil {
-				return fmt.Errorf("failed to print test result (%w)", err)
+			var resultsTable table.Table
+			{
+				err := printTestResult(out, filteredResults, responses, rc, &resultsTable, test.Fs, resourcePath)
+				if err != nil {
+					return fmt.Errorf("failed to print test result (%w)", err)
+				}
 			}
-			table.AddFailed(t.RawRows...)
+			{
+				err := printCheckResult(out, test.Test.Checks, responses, rc, &resultsTable)
+				if err != nil {
+					return fmt.Errorf("failed to print test result (%w)", err)
+				}
+			}
+			fullTable.AddFailed(resultsTable.RawRows...)
+			printer := table.NewTablePrinter(out)
+			fmt.Fprintln(out)
+			printer.Print(resultsTable.Rows(detailedResults))
+			fmt.Fprintln(out)
 		}
 	}
 	if !failOnly {
@@ -136,7 +149,7 @@ func testCommandExecute(
 	fmt.Fprintln(out)
 	if rc.Fail > 0 {
 		if !failOnly {
-			printFailedTestResult(out, table, detailedResults)
+			printFailedTestResult(out, fullTable, detailedResults)
 		}
 		return fmt.Errorf("%d tests failed", rc.Fail)
 	}
diff --git a/cmd/cli/kubectl-kyverno/commands/test/output.go b/cmd/cli/kubectl-kyverno/commands/test/output.go
index a885112725..a19898f808 100644
--- a/cmd/cli/kubectl-kyverno/commands/test/output.go
+++ b/cmd/cli/kubectl-kyverno/commands/test/output.go
@@ -1,30 +1,174 @@
 package test
 
 import (
+	"context"
 	"fmt"
 	"io"
 
 	"github.com/go-git/go-billy/v5"
+	"github.com/kyverno/kyverno-json/pkg/engine/assert"
 	policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
 	"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/apis/v1alpha1"
 	"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/output/color"
 	"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/output/table"
 	engineapi "github.com/kyverno/kyverno/pkg/engine/api"
+	"k8s.io/apimachinery/pkg/runtime"
 )
 
+func printCheckResult(
+	out io.Writer,
+	checks []v1alpha1.CheckResult,
+	responses []engineapi.EngineResponse,
+	rc *resultCounts,
+	resultsTable *table.Table,
+) error {
+	testCount := 1
+	for _, check := range checks {
+		// filter engine responses
+		matchingEngineResponses := responses
+		// 1. by resource
+		if check.Match.Resource != nil {
+			var filtered []engineapi.EngineResponse
+			for _, response := range matchingEngineResponses {
+				errs, err := assert.Validate(context.Background(), check.Match.Resource.Value, response.Resource.UnstructuredContent(), nil)
+				if err != nil {
+					return err
+				}
+				if len(errs) == 0 {
+					filtered = append(filtered, response)
+				}
+			}
+			matchingEngineResponses = filtered
+		}
+		// 2. by policy
+		if check.Match.Policy != nil {
+			var filtered []engineapi.EngineResponse
+			for _, response := range matchingEngineResponses {
+				data, err := runtime.DefaultUnstructuredConverter.ToUnstructured(response.Policy().MetaObject())
+				if err != nil {
+					return err
+				}
+				errs, err := assert.Validate(context.Background(), check.Match.Policy.Value, data, nil)
+				if err != nil {
+					return err
+				}
+				if len(errs) == 0 {
+					filtered = append(filtered, response)
+				}
+			}
+			matchingEngineResponses = filtered
+		}
+		for _, response := range matchingEngineResponses {
+			// filter rule responses
+			matchingRuleResponses := response.PolicyResponse.Rules
+			if check.Match.Rule != nil {
+				var filtered []engineapi.RuleResponse
+				for _, response := range matchingRuleResponses {
+					data := map[string]any{
+						"name": response.Name(),
+					}
+					errs, err := assert.Validate(context.Background(), check.Match.Rule.Value, data, nil)
+					if err != nil {
+						return err
+					}
+					if len(errs) == 0 {
+						filtered = append(filtered, response)
+					}
+				}
+				matchingRuleResponses = filtered
+			}
+			for _, rule := range matchingRuleResponses {
+				// perform check
+				data := map[string]any{
+					"name":     rule.Name(),
+					"ruleType": rule.RuleType(),
+					"message":  rule.Message(),
+					"status":   string(rule.Status()),
+					// generatedResource unstructured.Unstructured
+					// patchedTarget *unstructured.Unstructured
+					// patchedTargetParentResourceGVR metav1.GroupVersionResource
+					// patchedTargetSubresourceName string
+					// podSecurityChecks contains pod security checks (only if this is a pod security rule)
+					"podSecurityChecks": rule.PodSecurityChecks(),
+					"exception ":        rule.Exception(),
+				}
+				if check.Assert.Value != nil {
+					errs, err := assert.Validate(context.Background(), check.Assert.Value, data, nil)
+					if err != nil {
+						return err
+					}
+					row := table.Row{
+						RowCompact: table.RowCompact{
+							ID:        testCount,
+							Policy:    color.Policy("", response.Policy().GetName()),
+							Rule:      color.Rule(rule.Name()),
+							Resource:  color.Resource(response.Resource.GetKind(), response.Resource.GetNamespace(), response.Resource.GetName()),
+							IsFailure: len(errs) != 0,
+						},
+						Message: rule.Message(),
+					}
+					if len(errs) == 0 {
+						row.Result = color.ResultPass()
+						row.Reason = "Ok"
+						if rule.Status() == engineapi.RuleStatusSkip {
+							rc.Skip++
+						} else {
+							rc.Pass++
+						}
+					} else {
+						row.Result = color.ResultFail()
+						row.Reason = errs.ToAggregate().Error()
+						rc.Fail++
+					}
+					resultsTable.Add(row)
+					testCount++
+				}
+				if check.Error.Value != nil {
+					errs, err := assert.Validate(context.Background(), check.Error.Value, data, nil)
+					if err != nil {
+						return err
+					}
+					row := table.Row{
+						RowCompact: table.RowCompact{
+							ID:        testCount,
+							Policy:    color.Policy("", response.Policy().GetName()),
+							Rule:      color.Rule(rule.Name()),
+							Resource:  color.Resource(response.Resource.GetKind(), response.Resource.GetNamespace(), response.Resource.GetName()),
+							IsFailure: len(errs) != 0,
+						},
+						Message: rule.Message(),
+					}
+					if len(errs) != 0 {
+						row.Result = color.ResultPass()
+						row.Reason = errs.ToAggregate().Error()
+						if rule.Status() == engineapi.RuleStatusSkip {
+							rc.Skip++
+						} else {
+							rc.Pass++
+						}
+					} else {
+						row.Result = color.ResultFail()
+						row.Reason = "The assertion succeeded but was expected to fail"
+						rc.Fail++
+					}
+					resultsTable.Add(row)
+					testCount++
+				}
+			}
+		}
+	}
+	return nil
+}
+
 func printTestResult(
 	out io.Writer,
 	tests []v1alpha1.TestResult,
 	responses []engineapi.EngineResponse,
 	rc *resultCounts,
-	failOnly bool,
-	detailedResults bool,
+	resultsTable *table.Table,
 	fs billy.Filesystem,
 	resoucePath string,
-) (table.Table, error) {
-	printer := table.NewTablePrinter(out)
-	var resultsTable table.Table
-	var countDeprecatedResource int
+) error {
 	testCount := 1
 	for _, test := range tests {
 		// lookup matching engine responses (without the resource name)
@@ -36,7 +180,6 @@ func printTestResult(
 		if test.Resources != nil {
 			resources = append(resources, test.Resources...)
 		} else if test.Resource != "" {
-			countDeprecatedResource++
 			resources = append(resources, test.Resource)
 		}
 		for _, resource := range resources {
@@ -116,10 +259,7 @@ func printTestResult(
 			}
 		}
 	}
-	fmt.Fprintln(out)
-	printer.Print(resultsTable.Rows(detailedResults))
-	fmt.Fprintln(out)
-	return resultsTable, nil
+	return nil
 }
 
 func printFailedTestResult(out io.Writer, resultsTable table.Table, detailedResults bool) {
diff --git a/go.mod b/go.mod
index 2922cdf05f..9476b36a4d 100644
--- a/go.mod
+++ b/go.mod
@@ -30,6 +30,7 @@ require (
 	github.com/julienschmidt/httprouter v1.3.0
 	github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23
 	github.com/kyverno/go-jmespath v0.4.1-0.20231124160150-95e59c162877
+	github.com/kyverno/kyverno-json v0.0.1
 	github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7
 	github.com/notaryproject/notation-core-go v1.0.2
 	github.com/notaryproject/notation-go v1.0.1
@@ -92,6 +93,11 @@ require (
 
 require github.com/open-policy-agent/gatekeeper/v3 v3.14.0 // indirect
 
+require (
+	github.com/jmespath-community/go-jmespath v1.1.2-0.20231004164315-78945398586a // indirect
+	github.com/smarty/assertions v1.15.1 // indirect
+)
+
 require (
 	cloud.google.com/go/compute v1.23.3 // indirect
 	cloud.google.com/go/compute/metadata v0.2.3 // indirect
diff --git a/go.sum b/go.sum
index f38f35e81f..889384f3ec 100644
--- a/go.sum
+++ b/go.sum
@@ -547,6 +547,8 @@ github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhR
 github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
 github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
 github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
+github.com/jmespath-community/go-jmespath v1.1.2-0.20231004164315-78945398586a h1:8W5d74FhEWTJPnFwpDDxbwUK3pPLUbY4RlfN2uzTTSE=
+github.com/jmespath-community/go-jmespath v1.1.2-0.20231004164315-78945398586a/go.mod h1:4gOyFJsR/Gk+05RgTKYrifT7tBPWD8Lubtb5jRrfy9I=
 github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
@@ -588,6 +590,8 @@ github.com/kyverno/go-jmespath v0.4.1-0.20231124160150-95e59c162877 h1:XOLJNGX/q
 github.com/kyverno/go-jmespath v0.4.1-0.20231124160150-95e59c162877/go.mod h1:yzDHaKovQy16rjN4kFnjF+IdNoN4p1ndw+va6+B8zUU=
 github.com/kyverno/go-jmespath/internal/testify v1.5.2-0.20230630133209-945021c749d9 h1:lL311dF3a2aeNibJj8v+uhFU3XkvRHZmCtAdSPOrQYY=
 github.com/kyverno/go-jmespath/internal/testify v1.5.2-0.20230630133209-945021c749d9/go.mod h1:XRxUGHIiCy1WYma1CdfdO1WOhIe8dLPTENaZr5D1ex4=
+github.com/kyverno/kyverno-json v0.0.1 h1:2d3k1M0YCWRz9r5fdHkIMesChPbmtSYqR6qk+2s05b0=
+github.com/kyverno/kyverno-json v0.0.1/go.mod h1:7lNc9nnrNYC1Pbn/Qd5acyoRXa6sqBrZulc6Rg64q7w=
 github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7 h1:k/1ku0yehLCPqERCHkIHMDqDg1R02AcCScRuHbamU3s=
 github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7/go.mod h1:YR/zYthNdWfO8+0IOyHDcIDBBBS2JMnYUIwSsnwmRqU=
 github.com/letsencrypt/boulder v0.0.0-20240122173420-ce5632b480f0 h1:Ixlk3bGcKTpJeRujQ/YsO7aKq4CIHvBLodPcAzp/QZg=
@@ -781,11 +785,13 @@ github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EE
 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY=
 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
+github.com/smarty/assertions v1.15.1 h1:812oFiXI+G55vxsFf+8bIZ1ux30qtkdqzKbEFwyX3Tk=
+github.com/smarty/assertions v1.15.1/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0=
 github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
-github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
+github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
 github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
 github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
 github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=