Developer guides
Verify a custom Apex Check
Use this page to verify a custom Apex Check before deployment. This is not a Setup or Flow walkthrough. Administrators should use the Flow, configuration, and evaluation guides.
Use this page after creating a class that implements rhc.RecordHealthCheckPlugin. The checks
described here help prove that the class handles 1 to 200 records safely before an administrator
uses it in a Check.
What the verification proves
Section titled “What the verification proves”The installed rhc.RecordHealthCheckContractTest class calls your plugin with 1, 10, 50, and 200
record IDs. It verifies that the plugin:
- does not use more SOQL queries merely because more record IDs were supplied;
- returns exactly one outcome for every requested record ID and no others;
- does not create, update, or delete Salesforce records;
- does not make callouts, enqueue Queueable Apex, call a future method, or send email; and
- returns the expected result without exposing Found or Expected values when you supply an optional least-privilege test setup.
The package’s AccountHasRecentActivityCheck example passes this test. The package tests also use an
intentionally inefficient example to confirm that query use that grows with the number of records is
rejected.
What still requires a code review
Section titled “What still requires a code review”Passing the contract test does not prove everything about custom Apex. Review the plugin source too:
- The class declaration must use
global with sharing. - Every SOQL query must enforce the intended object, field, and record access. The package example
uses
WITH USER_MODE. - A SOQL query must not run inside a loop over
scope.recordIds. - Record-specific problems should return an outcome for that record. An uncaught exception can turn every result in the request into an error.
Apex does not provide a counter that tells the test whether a custom query used user mode. Running a
test with System.runAs changes the user, but it does not by itself prove that every query enforced
that user’s object and field access. This is why both the contract test and a source review are
required.
Create the plugin and its contract test
Section titled “Create the plugin and its contract test”Start with these repository templates:
Copy both templates into your Salesforce project’s Apex classes folder. Then:
- Rename the plugin class and its test class.
- Replace the example object, fields, and grouped query with the data your Check needs.
- Keep one query outside the record loop. Use the returned records to build a map, then loop over
scope.recordIdsto create one outcome per ID. - In the test class, make
newCheck()return a new instance of your plugin. - Make
testData()return test data that can create scopes containing 1, 10, 50, and 200 records. - Keep the test method that calls
verifyContract().
The test has this basic shape:
@IsTestglobal class AccountDataQualityCheckTest extends rhc.RecordHealthCheckContractTest { global override rhc.RecordHealthCheckPlugin newCheck() { return new AccountDataQualityCheck(); }
global override rhc.RecordHealthCheckContractTestData testData() { return new AccountDataQualityCheckTestData(); }
@IsTest static void verifiesRecordHealthCheckContract() { new AccountDataQualityCheckTest().verifyContract(); }}AccountDataQualityCheckTestData in this example is a test-data class your team creates by following
the contract-test template. It must create the requested number of records and return a
rhc.RecordHealthCheckScope containing their IDs.
Optional: Verify behavior for a user with limited access
Section titled “Optional: Verify behavior for a user with limited access”Override permissionFixture() only when the test creates a real access difference. For example,
create a user who cannot read a field the plugin needs, then expect
UNABLE_TO_EVALUATE for a record that uses that field.
The test passes this permission check only when:
- the expected record has the expected Status;
- Found Value is empty; and
- Expected Value is empty.
Creating a second user without removing access to a relevant record or field does not provide useful permission evidence.
Use the fluent test facade for a focused assertion
Section titled “Use the fluent test facade for a focused assertion”Inside an Apex test, rhc.RecordHealthCheckPluginTest.verify(plugin, scope) returns a
rhc.RecordHealthCheckPluginVerification. Chain assertComplete(), assertNoSideEffects(), and
assertRenderable() when one focused test needs to prove result coverage, guarded side effects,
and typed rendering. The facade throws TEST_CONTEXT_REQUIRED outside an Apex test and is not a
production execution entry point. Use RecordHealthCheckContractTest for the complete 1, 10, 50,
and 200-record contract suite.
Before activating the Check
Section titled “Before activating the Check”- Run the plugin’s Apex tests, including the contract test.
- Review every SOQL query and confirm its access mode.
- Test the complete Check Set with a realistic Batch size in a sandbox. Several individually safe Checks still share the limits of each Batch transaction.
- If the plugin fails verification, keep the Check inactive until the code is corrected. Do not silently skip it or treat an unexplained exclusion as a passing result.