From aer
This skill should be used when the user wants to write or run Apex unit tests with aer (the Apex Execution Runtime) — "run aer tests", "run my Apex tests", "run a single test method", "write an Apex test", "debug a failing Apex test", "show System.debug output", "check Apex code coverage", or "find a flaky Apex test". Covers the `aer test` command and its selection / configuration / output / debugging flags, `@IsTest` authoring conventions, and how to read PASS/FAIL output. Do NOT use for deploying metadata, running the `aer server` API, or executing anonymous Apex (`aer exec`).
How this skill is triggered — by the user, by Claude, or both
Slash command
/aer:aer-testThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**aer** (Apex Execution Runtime) is an Apex interpreter and test runner written.
aer (Apex Execution Runtime) is an Apex interpreter and test runner written.
aer test executes @IsTest methods locally — no Salesforce org, no deploy — and
reports PASS/FAIL. It evaluates Apex, SOQL/SOSL, DML, triggers, and a large part of the
standard library against an in-memory database seeded from local object metadata.
Requires: the
aerbinary onPATH. Install via Homebrew (macOS/Linux)brew install octoberswimmer/tap/aeror a prebuilt archive from aer-dist releases. Seereferences/cli-reference.mdfor all options. Running tests beyond 100 test methods requires a license — see licensing.
| File | Read it when |
|---|---|
references/cli-reference.md | You need the full aer test flag list — selection, configuration, output, debugging, and licensing. |
references/writing-tests.md | You are authoring .cls test classes — @IsTest, assertions, Test.startTest, mocking, runAs, @TestSetup, and naming/file conventions. |
references/debugging.md | A test fails, errors, or flakes and you need to find out why — --verbose, --all-exceptions, --skip-errors, --trace/--profile, --runs, --watch. |
aer test # discover and run every @IsTest method under the cwd
aer test force-app # run all tests in a directory (force-app is the SFDX default)
aer test force-app -f MyTest # run only test methods/classes matching "MyTest"
aer test force-app -v # verbose: show System.debug output
aer test force-app -q # quiet: only failures and the summary
aer test force-app/main/default/classes/Foo.cls # one file (workspace auto-detected for deps)
Output is one line per test method (PASS/FAIL) plus a summary. FAIL lines include the
exception type, message, and Apex stack trace. A non-zero exit code means at least one test
failed — rely on the exit code in scripts, not on scraping text.
.cls/.trigger and object metadata under it. This is the
safest form — all dependencies resolve. Prefer it when in doubt..cls/.trigger file triggers workspace auto-detection: aer walks up to the
enclosing sfdx-project.json / package.xml, loads the whole workspace so sibling classes
resolve, then auto-applies --filter-path so only tests from that file run.| Goal | Flag |
|---|---|
| Match test name (substring or glob, repeatable) | -f, --filter 'account_*' |
Match by source file path (prefix or ** glob) | --filter-path 'force-app/main/default/classes/**' |
Exclude by name (applied after --filter) | --skip flaky_test |
| Run only tests targeting a class/trigger/etc. | --for ApexClass:AccountService |
Include @IsTest(critical=true) tests | --critical |
| Preview selection without running | -n, --dry-run |
--filter matches either a class name or a method name, as a substring or a glob. --for
selects tests annotated @IsTest(testFor='ApexClass:AccountService') (class- or method-level).
--critical adds critical tests to the run; used alone it runs only critical tests.
See references/cli-reference.md for the full matrix.
aer test force-app -f AccountServiceTest.creates_default_contact # one method, fully qualified
aer test force-app --for ApexClass:AccountService # everything that tests AccountService
aer test force-app --dry-run # list what would run
Tests often need metadata, packages, or org settings that aren't in the source directory:
| Need | Flag |
|---|---|
Load managed packages (.pkg files) | --package foo.pkg / --package-dir ./packages/ |
| Treat loaded code as belonging to a namespace | -d, --default-namespace acme |
| Enable optional platform features | --feature PersonAccounts --feature MultiCurrency |
| Assign permission sets to the test user (custom-field/object FLS) | -p, --assign-perms My_Perm_Set |
| Load certificate signing keys (Crypto/JWT) | --certificate-dir ./certs/ |
| Mark org as a sandbox | --sandbox |
Pin the clock for Date.today()/now() | --faketime 2026-01-15T09:00:00-08:00 |
| Run with DML disabled (read-only org) | --read-only |
No such column 'Foo__c' on entity 'Bar'when the field exists in your source? That's field-level security, not a missing field. The default test user has the System Administrator profile, which grants no implicit access to custom objects/fields (just like a real org). Grant access with--assign-perms <PermSet>(repeatable). Seereferences/writing-tests.md.
--feature accepts: PersonAccounts, HealthCloud, MultiCurrency, FieldService,
Knowledge, ExperienceCloud, Scheduler, and more — run aer test --help for the current
list. Full descriptions in references/cli-reference.md.
Text output goes to stdout by default. Machine formats coexist with it (except --json,
which replaces stdout text):
aer test force-app --junit results.xml # JUnit XML (for CI) + text on stdout
aer test force-app --json results.jsonl # JSONL stream (replaces stdout text)
aer test force-app --coverage cov.xml # code coverage (Cobertura by default)
aer test force-app --coverage cov.json --coverage-format json
aer test force-app -v # show System.debug — required to see debug output
aer test force-app -q # only failures + summary
System.debug(...) output only appears with -v/--verbose. If a user asks "why isn't my
debug printing," add -v. Repeat (-vv) for more runtime detail.
Start with the FAIL line's exception and stack trace, then escalate:
aer test force-app -f failing_test -v # see System.debug leading up to the failure
aer test force-app -f failing_test --all-exceptions # show details for ALL caught exceptions, not just uncaught
aer test force-app --skip-errors # run tests whose deps compile, despite parse/type errors elsewhere
aer test force-app -f flaky --runs 20 # run 20× to surface intermittent failures (tagged "(run i/N)")
aer test force-app -f my_test --watch # re-run on file changes while you iterate
For deep dives — execution traces, CPU profiles, pinning the clock, and inspecting the database —
see references/debugging.md.
Author tests as @IsTest classes in .cls files. The essentials:
AccountServiceTest.cls → class AccountServiceTest).testCreateContact, should_create_contact). Only when
starting a new codebase, or when existing names are inconsistent, fall back to BDD-style
snake_case describing the behavior (creates_default_contact_for_new_account).testMethod is a reserved word in Apex — never name a method testMethod.@IsTest
private class AccountServiceTest {
@IsTest
static void creates_default_contact_for_new_account() {
Account a = new Account(Name = 'Acme');
insert a;
Test.startTest();
AccountService.ensureDefaultContact(a.Id);
Test.stopTest();
List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :a.Id];
Assert.areEqual(1, contacts.size(), 'one default contact should be created');
}
}
aer supports the modern Assert class (Assert.areEqual, Assert.isTrue, Assert.isNull,
Assert.isInstanceOfType, Assert.fail, …) and the legacy System.assert* family, plus
Test.startTest/stopTest, Test.setMock, Test.createStub, System.runAs, and @TestSetup.
Full authoring guide — assertions, mocking patterns, permissions/FLS, and selecting tests by
@IsTest annotation — in references/writing-tests.md.
Don't claim tests pass — show it. After a run:
Provides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.
npx claudepluginhub octoberswimmer/agent-skills --plugin aer