---
name: agent-action-unit-tests
description: "Apex test patterns for @InvocableMethod agent actions: per-branch coverage, bulk safety, deterministic assertions. NOT for UI/LWC testing or agent conversational quality scoring."
category: agentforce
salesforce-version: "Spring '25+"
well-architected-pillars:
  - Reliability
  - Operational Excellence
triggers:
  - "my invocable action has low coverage"
  - "how do I test every reason_code branch"
  - "bulk test for agent action"
  - "flaky test on invocable class"
tags:
  - agentforce
  - apex-tests
  - invocable
  - coverage
inputs:
  - "@InvocableMethod class"
outputs:
  - "Test class with per-branch assertions + bulk test"
dependencies: []
version: 1.0.0
author: Pranav Nagrecha
updated: 2026-04-17
---

# Agent Action Unit Tests

Agent actions are Apex classes with `@InvocableMethod`. They need the same testing rigor as any deployed Apex — plus two extras: every reason_code branch must be asserted, and the bulk-size contract (≤200 per invocation) must be verified.

## When to Use

Every @InvocableMethod class before Gate C review. Mandatory for Agentforce production deployment.

Typical trigger phrases that should route to this skill: `my invocable action has low coverage`, `how do I test every reason_code branch`, `bulk test for agent action`, `flaky test on invocable class`.

## Recommended Workflow

1. List every reason_code the action can return; write one test per code.
2. Write a bulk test that submits 200 Request records and asserts 200 Response records come back — no Limits.getDMLStatements() >150 failures.
3. For callout actions, use `Test.setMock` with canned 200/4xx/5xx responses and assert the branch classification.
4. Assert on `Response.reason_code`, never on `Response.user_message` text (the text can change for UX; the code is the contract).
5. Run `sf apex run test -c` and confirm per-class coverage ≥85% AND every reason_code has an explicit assertion.

## Key Considerations

- Coverage % alone is misleading; the requirement is per-reason-code assertion coverage.
- Don't assert on user_message — it's UX copy; it will change.
- Mock every callout; no real HTTP from tests.

## Worked Examples (see `references/examples.md`)

- *Per-reason-code test matrix* — CloseCaseAction returns OK | VALIDATION_BLOCKED | UNKNOWN.
- *Bulk-safety harness* — Agent batches 200 requests into one action invocation.

## Common Gotchas (see `references/gotchas.md`)

- **Test.startTest/stopTest required for async** — Queueable from inside Invocable doesn't run in test without the boundary.
- **@InvocableVariable default values** — Missing fields on Request become null, not default.
- **Asserting on user_message strings** — UX change breaks 40 tests at once.

## Top LLM Anti-Patterns (full list in `references/llm-anti-patterns.md`)

- Testing only the happy path with coverage padding.
- Asserting on user_message text.
- Skipping the bulk test because 'the agent only sends one at a time right now'.

## Official Sources Used

- Agentforce Developer Guide — https://developer.salesforce.com/docs/einstein/genai/guide/agentforce.html
- Einstein Trust Layer — https://help.salesforce.com/s/articleView?id=sf.generative_ai_trust_layer.htm
- Invocable Actions (Apex) — https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_classes_invocable_action.htm
- Agentforce Testing Center — https://help.salesforce.com/s/articleView?id=sf.agentforce_testing_center.htm
