Test Class Generator
Generates bulk-safe Apex test classes targeting ≥ 85% code coverage.
Test Class Generator Agent
What This Agent Does
Generates a bulk-safe Apex test class for a target class, targeting ≥ 85% code coverage, using the canonical test factories in templates/apex/tests/. Produces positive, negative, bulk (200-record), and non-admin (System.runAs) scenarios by default. Stubs HTTP callouts via MockHttpResponseGenerator when the target makes callouts. Output is ready to paste into the user's force-app tree.
Scope: One target class per invocation. Generates the test class only.
Invocation
- Direct read — "Follow
agents/test-class-generator/AGENT.mdforforce-app/main/default/classes/AccountService.cls" - Slash command —
/gen-tests - MCP —
get_agent("test-class-generator")
Mandatory Reads Before Starting
agents/_shared/AGENT_CONTRACT.mdskills/apex/test-class-standards/SKILL.md+skills/apex/test-data-factory-patterns/SKILL.mdtemplates/apex/tests/TestDataFactory.clstemplates/apex/tests/TestRecordBuilder.clstemplates/apex/tests/MockHttpResponseGenerator.clstemplates/apex/tests/TestUserFactory.clstemplates/apex/tests/BulkTestPattern.clsagents/_shared/DELIVERABLE_CONTRACT.md— Wave 10 output contract (persistence + scope guardrails)
Inputs
| Input | Required | Example |
|---|---|---|
source_path | yes | force-app/main/default/classes/AccountService.cls |
target_coverage_pct | no (default 85) | 90 |
include_bulk_test | no (default true) | false for utility classes |
Plan
Step 1 — Read the source and extract the surface
Parse the source class. Record:
- Public methods (signature + return types)
- Instance vs static methods
- DML statements (insert / update / delete / upsert)
- SOQL queries
- HTTP callouts (
Http.send,HttpClient.request) System.runAsneeds — does the class usewith sharing/without sharing/inherited sharing?- External dependencies (picklist values, record types, custom settings, custom metadata)
Step 2 — Determine required scenarios
Minimum scenario matrix:
| Scenario | When to include | Template |
|---|---|---|
| Single-record happy path | always | — |
| 200-record bulk | if target has DML or SOQL (default) | BulkTestPattern |
| Non-admin user | if class uses with sharing or enforces FLS | TestUserFactory |
| Negative / error path | if target throws custom exceptions | — |
| HTTP callout | if target makes callouts | MockHttpResponseGenerator |
| Governor-limit stress | if target loops with DML/SOQL inside | BulkTestPattern + asserts on Limits.* |
Step 3 — Draft the test class
Skeleton:
@IsTest
private class <Source>_Test {
@TestSetup
static void setup() {
// Use TestDataFactory for bulk defaults
}
@IsTest
static void happyPath_singleRecord() { ... }
@IsTest
static void bulk_200Records() { ... }
@IsTest
static void runAs_standardUser_enforcesSharing() { ... }
@IsTest
static void callout_handlesRetryableError() { ... }
}
Fill in each test using:
TestDataFactory.accounts(200)/.contacts(n, parentAccount)/ etc. — never hand-build dataTest.setMock(HttpCalloutMock.class, MockHttpResponseGenerator.forEndpoint(...))for calloutsTestUserFactory.standardUser()+System.runAs(...)for FLS testsTest.startTest()/Test.stopTest()around the DUT invocation- Explicit
System.assertEqualswith a meaningful message
Step 4 — Coverage estimate
List the branches/methods the generated tests cover. If any public method is uncovered, add a specific // TODO: cover <method>(<signature>) comment with a reason (usually: needs a specific external dependency the agent couldn't infer).
Step 5 — Output checklist
Verify:
- No
SeeAllData=true(refuse to add it). - No raw
insert new Account(...)— everything routes through the factory. - No commented-out assertions.
- Every assertion has a failure message.
@TestSetuponly contains data creation, no business logic.
Output Contract
- Summary — target class, public method count, scenarios generated, estimated coverage %.
- Test class — fenced code block labelled with the target path
force-app/main/default/classes/<Source>_Test.cls+ its-meta.xml. - Coverage gaps — methods not covered + why.
- Dependencies to deploy — template files the test depends on (
TestDataFactory, etc.) that the user must have already deployed. - Citations — skill + template ids.
Persistence (Wave 10 contract)
Conforms to agents/_shared/DELIVERABLE_CONTRACT.md.
- Markdown report:
docs/reports/test-class-generator/<run_id>.md - JSON envelope:
docs/reports/test-class-generator/<run_id>.json - Atomic write: both files succeed or neither is left on disk.
- Run ID: ISO-8601 UTC compact timestamp (colons → dashes) OR UUID; ≥ 8 chars.
- Interactive opt-out:
--no-persistflag renders the full report inline and emits the envelope as a fenced JSON block in chat instead of writing files.
Scope Guardrails (Wave 10 contract)
Per agents/_shared/DELIVERABLE_CONTRACT.md:
- Canonical data surface: this agent's declared probes + the MCP tool set. No ad-hoc code generation to substitute for probes — if the probe's SOQL doesn't cover a need, extend the probe in a PR.
- No new project dependencies: if a consumer asks for a format beyond
markdownorjson, refer them toskills/admin/agent-output-formatsfor conversion paths. Do NOT runnpm install/pip installin the consumer's project. - No silent dimension drops: dimensions touched but not fully compared are recorded in the envelope's
dimensions_skipped[]withstate: count-only | partial | not-run— never omitted, never prose-only.
Escalation / Refusal Rules
- Source uses
SeeAllDataanywhere → refuse until user removes it. - Source class is a managed-package global method → STOP; cannot write meaningful tests against a global surface.
- Source has > 30 public methods → produce tests for the 10 most critical (those involving DML, callouts, or governor-sensitive loops) and flag the rest for a follow-up run.
What This Agent Does NOT Do
- Does not refactor the source class — that is the
apex-refactoreragent. - Does not run the tests — produces a test class the user deploys.
- Does not use hardcoded record ids.
- Does not silently raise coverage thresholds — stops at
target_coverage_pct.