π TOPIC 6 β ANSWER SHEET (SEALED)
TESTING & TEST CLASSES β MODEL ANSWERS
06b_Topic06_Testing_TestClasses_Answer_Sheet.md
SEALED β the answers are the property of the learner who earned them. Do not read a section until you have WRITTEN your own answer (Incident, REDO, or Rapid-Fire) on paper or in a scratch file. The seal breaks once per section, in order. Read the workbook first; answer from memory; then compare. Where your answer differs, rewrite yours β the writing is the learning. The sheet answers: every INCIDENT (model answer), every REDO, every Retrieval Drill, the Capstone (model report + 3 regression tests + 2-minute script), all 20 Rapid-Fire, the 5 Interleaved Practice problems, and the One-Card Key.
M0 β THE MODULE MAP (MODEL SUMMARY)
- 1. The Green Build That Deployed a Bug β coverage β behavior; assertions must prove the code's promise on re-queried state. The coverage-farming org and the retry logic that broke in production.
- 2. The Test That Failed on Fridays β determinism: no calendar dependence (fixed dates), no shared static state (reset in
@TestSetup). The Friday-only failure and the serial number that leaked. - 3. The Callout Test That Called the Internet β mocks are mandatory:
HttpCalloutMock/WebServiceMock/static-resource mocks viaTest.setMock; success AND failure paths (500/timeout) are both testable β the mock owns the conversation. - 4. The 40-Minute Test That Deployed Nothing β three failures: overweight fixture (bulk = code paths, not rows), missing
startTest/stopTest(the window flushes async synchronously), asserting the fixture instead of the batch's effect. - 5. The Async Test That Tested Nothing β async work enqueued outside the window runs after the test: green-but-untested. Rule: enqueue inside
startTest; assert afterstopTest. Module 3 tie-ins: callout mock + retry/dead-letter assertions. - 6. The runAs Test That Ran as the Wrong User β tests run in system context by default; sharing/FLS tests require
System.runAs(user)(real user, standard profile). Assert the user's view + FLS-stripped fields. - 7. The Scheduled Job That Never Fired β
Test.getCronTriggerproves the schedule row, not the execution; scheduled jobs fire inside the window. Two legs: mechanics + behavior. - 8. The Exception Test That Swallowed the Bug β try/catch with no assertion = worse than no test;
expectedExceptionsfor throwing code, behavior assertions (retry counter/dead-letter) for handling code. - 9. π Capstone β The Suite That Deployed the Org β the testing contract: behavior claims, re-queried state, user's context, async window, mocked callouts, no swallowed exceptions; 4 audit answers + 4-component checklist + 3 regression tests.
The contract sentence (memorize): "Every test asserts a behavior claim the code promises β measured on re-queried state, under the user's context, inside the async window, with mocks for every callout, and never a swallowed exception."
INCIDENT 1 β MODEL ANSWER
What the broken assertion proved vs what the behavior requires: the catch(Exception e) proved only "no exception escaped" β a process claim. The sync contract promises a state change: invoices with Synced__c = false become Synced__c = true after the queueable runs. Coverage counted the lines executed (the run() call and its catch), not the behavior (the status field updated). The suite's "95%" was line coverage of a process assertion.
The corrected test: re-query the records after Test.stopTest() (the window flushes the queueable) and assert the exact promised state:
System.assertEquals(2, [SELECT COUNT() FROM Invoice__c WHERE Synced__c = true])β the exact count of synced rows;- assert the specific records (
inv.Id,inv2.Idin the synced set) β the promise kept on the right rows; - assert the failed path's retry counter (
Retry_Count__c = 1) β the failure behavior, not just the success. If the code had usedSecurity.stripInaccessible/WITH USER_MODE, the test also asserts the stripped shape (see Incident 6).
Coverage is a byproduct: the deploy threshold is 75%+ as a floor; a 95% process-assertion suite is worthless, a 65% behavior suite ships. In an interview: "Coverage proves the code ran; the assertion proves the promise."
INCIDENT 1 β RETRIEVAL DRILL ANSWERS
- What does the green build + broken production prove? β Coverage β behavior; the suite asserted process (no exception), the contract was a state change (Synced flag). Line coverage counted execution, not the promise.
- The assertion formula. β The promised state change, re-queried, exact values, on the right records, success AND failure paths.
- "Process assertion" vs "behavior assertion" β define each with an example. β Process: "no exception / record exists / code ran" (the broken
catchtest). Behavior: "the invoice row isSyncedafter the flush" (the corrected test). - How to re-query and assert an updated record. β
[SELECT Status__c FROM Invoice__c WHERE Id = :inv.Id]afterTest.stopTest(); assert the exact field value; assert exact counts on the affected set. - How would you present coverage in an interview? β "Coverage proves the code ran; assertions prove the promise. I treat 75% as the floor and behavior coverage as the metric."
INCIDENT 2 β MODEL ANSWER
The two determinism killers (name them as a pair): (1) Calendar dependence β Date.today(), System.now(), DateTime.now() computed at test time: the test's expected values must not depend on when the test runs (the Monday check failed only on Fridays; the invoice-due calculation failed only when a month boundary fell between setup and assertion). (2) Shared static state β @TestSetup runs once per class, and static variables are not reset between test methods by default: a System.serialNumber counter incremented in setup leaked into the second test's assertions (the serial the test expected β the serial the setup consumed).
The fixes: (1) Fixed date in @TestSetup: Date fixedDate = Date.newInstance(2026, 8, 20); β the setup creates invoices with Due_Date__c = fixedDate, the test computes expectations from fixedDate, and the assertion System.assertEquals(fixedDate.addDays(1), ...) is time-independent (a fixed reference date also makes tests deterministic across orgs β no timezone variance). (2) Static-state reset: initialize the static System.serialNumber in each @TestSetup/test (or use @TestSetup for data and reset statics in each test method); a clean-slate static guarantee: System.resetSerialNumber() in setup β the class under test must expose reset or the test creates it fresh.
The Friday test explained: the calendar check System.assertEquals('Monday', dayOfWeek) depended on the run date; on Fridays it failed, and the fix (fixed reference date, never today()) made the test deterministic.
INCIDENT 2 β RETRIEVAL DRILL ANSWERS
- The two determinism killers. β Calendar dependence (
today()/now()in tests) and shared static state (statics not reset between methods). - Why does
Date.today()break a test? β The expected values move with the run date β timezone, DST, and month boundaries make the same test fail or pass by when it runs. - The setup fix for calendar dependence. β A fixed reference date (
Date.newInstance(2026, 8, 20)); compute expectations from it; assert against it. Tests become time-independent. - Why does
@TestSetupmake static state worse? β Setup runs once per class and statics are not reset per method β the second test inherits the first's static residue. - The
System.serialNumberfix. β Reset the static in each test/setup (aresetSerialNumbermethod on the class or fresh initialization per method) β the same test, same result, every run.
INCIDENT 3 β MODEL ANSWER
The mocking rule (state as a law): Tests must never perform real callouts. The engine enforces it: Http.send without a registered mock throws CalloutException β and in the "worse" case (permissive environment), the test actually hits the real endpoint and mutates real external state (the 100 real records marked "synced"). Test.setMock(HttpCalloutMock.class, mock) is mandatory registration; the mock owns the entire conversation (request AND response), including the failures.
The mock classes (all four): (1) HttpCalloutMock β interface: HTTPResponse respond(HTTPRequest req); the test implements it and returns whatever the scenario needs (200, 500, empty body). (2) StaticResourceCalloutMock β returns a static resource body (canned large payloads). (3) MultiStaticResourceCalloutMock β different static-resource bodies per endpoint. (4) WebServiceMock β SOAP callouts. All registered via Test.setMock.
The success-path test (with request assertions β the senior detail): set the mock (200 + body), run the sync inside the window, assert the result and the conversation:
@isTest
static void testSyncSuccess() {
Test.setMock(HttpCalloutMock.class, new SuccessMock()); // 200 + body
Test.startTest(); BillingSync.run(); Test.stopTest();
System.assertEquals('Synced', [SELECT Status__c FROM Invoice__c WHERE Id = :inv.Id].Status__c);
// the mock captured the request β assert endpoint/method/headers the code actually sent:
System.assertEquals('https://billing.example.com/api/invoices', SuccessMock.capturedEndpoint);
System.assertEquals('POST', SuccessMock.capturedMethod);
}The failure-path test (the one that matters): the mock returns 500 (provider error) or throws CalloutException in respond (the timeout simulation β Module 3 Incident 8's 3:00 AM blip). Assert the retry behavior: Retry_Count__c = 1 (counter incremented), the retry queueable flushed by stopTest, and on the 3rd attempt the dead-letter Error_Log__c row + alert. The failure test is the resilience test β the one that would have caught the Module 3 blackout.
INCIDENT 3 β RETRIEVAL DRILL ANSWERS
- Why are real callouts forbidden β and what does the engine do? β Real calls mutate external state and are environment-dependent; the engine throws
CalloutExceptionwhenHttp.sendruns unmocked β the platform's mock-mandate. - The four mock classes + registration. β
HttpCalloutMock,StaticResourceCalloutMock,MultiStaticResourceCalloutMock,WebServiceMock; all viaTest.setMock. - What should the success test assert beyond "no exception"? β The promised state (Status = Synced) AND the conversation (endpoint, method, headers the code sent).
- Simulate a timeout with a mock. β A mock whose
respondthrowsCalloutException(or returns 500). - Which Module 3 incident does the failure test protect? β Incident 8's blackout (the 3:00 AM external outage + retry/dead-letter design).
INCIDENT 4 β MODEL ANSWER
The three design failures (the verdict):
- Fixture volume as a substitute for semantics β 50,000 DML calls to "look bulk"; bulk semantics (QueryLocator iteration, chunking, governor limits inside
execute) are exercised by a small fixture. Volume adds runtime + flakiness. - Missing
startTest/stopTestβ the batch enqueued outside the window runs truly async: the test can't reliably assert it, and the suite hits the deploy-timeout ceiling. - Asserting the fixture, not the effect β the rollup values were pre-set by the fixture; the assertion validated the fixture. The test must compare the batch's computed result to an independent expectation (a manual SUM).
The startTest/stopTest semantics (memorize): Test.startTest() resets governor limits and opens the async window; Test.stopTest() executes all async work enqueued inside the window synchronously β futures, queueables, batches (including finish()), scheduled jobs. Enqueue inside; assert after.
The corrected bulk test:
@isTest
static void testRollupComputes() {
Account p = new Account(Name='P'); insert p;
insert new List<Child__c>{ new Child__c(Parent__c=p.Id, Amount__c=100),
new Child__c(Parent__c=p.Id, Amount__c=200) };
Test.startTest();
Database.executeBatch(new RollupBatch(), 200);
Test.stopTest(); // batch + finish() run synchronously
Account result = [SELECT Rollup__c FROM Account WHERE Id = :p.Id];
System.assertEquals(300, result.Rollup__c); // the batch's effect vs manual SUM
}"Testing bulk" without a mountain of rows: a second small test asserts the batch's limit behavior within execute (Limits.getDMLRows()), plus chunking via a scope-size parameter β the code paths, verified.
INCIDENT 4 β RETRIEVAL DRILL ANSWERS
- The three design failures. β Overweight fixture (volume β semantics), missing startTest/stopTest (batch ran async/unobserved), asserting the fixture's pre-set values.
- What does startTest do β and what does stopTest flush? β startTest resets governor limits + opens the window; stopTest executes async work enqueued inside synchronously (futures, queueables, batches + finish, scheduled).
- Does the batch's
finish()run in the test? β Yes β when the batch is enqueued inside the window,stopTestruns it to completion,finish()included. - "Testing bulk" = testing what? β The bulk code paths: QueryLocator iteration, chunking/scope, governor limits inside
executeβ not row volume. - The corrected assertion compares what vs what? β The batch's computed
Rollup__c(re-queried) vs an independent manual SUM.
INCIDENT 5 β MODEL ANSWER
The async timing rules (the #1 async-testing question): async work enqueued outside the window executes after the test method completes β the test only observes the pre-execution world (the "0 synced" tell). Enqueued inside the window, Test.stopTest() flushes it synchronously: the queueable's execute runs before stopTest returns, and everything it chains (nested enqueues to the depth limit) runs too. The rule: enqueue inside startTest; assert after stopTest β applies to @future (invoke inside), Database.executeBatch (+ finish), System.enqueueJob, System.schedule, and platform-event-triggered flows.
The two failure modes: (1) executes-after-test β the work runs post-test; the test asserted pre-execution state and passed while verifying nothing (the org's 92% covered the enqueue line, not the sync); (2) never-observable β the work's effects land where no assertion can see them; production is the first run.
The corrected test (+ Module 3 tie-ins):
@isTest
static void testSyncSuccess() {
Test.setMock(HttpCalloutMock.class, new SuccessMock()); // I3: mock mandatory
Test.startTest();
BillingSync.enqueue(new List<Id>{ inv.Id, inv2.Id });
Test.stopTest(); // queueable executes NOW
System.assertEquals(2, [SELECT COUNT() FROM Invoice__c WHERE Synced__c = true]);
}
@isTest
static void testSyncTimeoutRetries() {
Test.setMock(HttpCalloutMock.class, new TimeoutMock()); // throws CalloutException
Test.startTest(); BillingSync.enqueue(ids); Test.stopTest();
System.assertEquals(1, [SELECT Retry_Count__c FROM Invoice__c WHERE Id = :inv.Id].Retry_Count__c);
// 3rd attempt: dead-letter Error_Log__c row (Module 3 Incident 8 contract)
}INCIDENT 5 β RETRIEVAL DRILL ANSWERS
- When does async work enqueued outside the window execute? β After the test method completes β unobservable; the test asserts a world where the work hasn't run.
- The one-line rule for testing async code. β Enqueue inside
startTest; assert afterstopTest. - What does the "0 synced" assertion reveal? β The queueable hadn't run yet β the test verified nothing (green-but-untested).
- The Module 3 tie-ins (name both). β The callout mock (
Test.setMock) and the retry/dead-letter assertions (TimeoutMock β Retry_Count = 1; max attempts β Error_Log__c row). - Does stopTest flush chained queueables? β Yes β everything enqueued inside the window, including chained queueables, executes synchronously at stopTest (to the depth limit).
INCIDENT 6 β MODEL ANSWER
The default-context trap: tests execute as the test-running user β system context, where sharing and FLS are not enforced. A security test without runAs asserts the admin's view β green and meaningless for the security behavior. System.runAs(user) { ... } runs the block under the given user's context: sharing rules, FLS, and permissions apply exactly as in production.
The constraints (know them): the runAs user must be a real user record created in the test; give it a standard profile (not system admin) and any needed PermissionSets; create it before runAs. runAs does NOT change: license limits for system operations, and it doesn't bypass test isolation.
The corrected security test (4 steps):
@isTest
static void testRepSeesOnlyOwned() {
User repA = TestUtil.createRep(); // 1: standard-profile user
Account mine = new Account(Name='Acme-1', OwnerId = repA.Id); insert mine; // 2: controlled ownership
Account others = new Account(Name='Acme-2', OwnerId = otherUser.Id); insert others;
System.runAs(repA) { // 3: runAs block
List<Account> r = AccountSearch.find('Acme');
System.assertEquals(1, r.size()); // 4: assert the USER's view
System.assertEquals('Acme-1', r[0].Name);
}
}The FLS assertion pattern (Module 5 Incident 2, as a test): inside runAs(repA), assert the sensitive fields are stripped: System.assertEquals(null, result.SSN__c) (the Security.stripInaccessible behavior) β or assert the WITH USER_MODE filtered shape. Security tests assert the user's result, not the code's result.
INCIDENT 6 β RETRIEVAL DRILL ANSWERS
- Who executes test code by default β and what does that hide? β The test-running user in system context; sharing and FLS behavior is invisible.
- What must a runAs user have (3)? β Real user record created in the test, standard profile (not admin), needed PermissionSets.
- What does runAs NOT change? β License limits (some system ops still run system-side) and test isolation (real data still invisible).
- The 4-step corrected security test. β Create standard-profile user β insert controlled-ownership records β
System.runAs(user) { ... }β assert the user's view (counts + specific records). - How do you assert FLS behavior? β Inside runAs: sensitive fields null (stripInaccessible) or the USER_MODE filtered shape.
INCIDENT 7 β MODEL ANSWER
The false-proof diagnosis: Test.getCronTrigger('Reminder') != null proves the schedule row was created β nothing about the job's execute. System.schedule creates the cron entry immediately; execution happens at the scheduled time, outside the test β unless scheduled inside the window, where stopTest flushes it synchronously (scheduled work is async work β Incidents 4/5's rule). The coverage dashboard showed the schedulable "covered" (the schedule call executed) while execute ran zero times in tests β production night 1 was the first run.
The correct pattern (memorize):
@isTest
static void testReminderSchedulesAndFires() {
Test.startTest();
String jobId = System.schedule('Reminder', '0 0 2 * * ?', new ReminderJob());
Test.stopTest(); // scheduled job executes NOW
System.assert(Test.getCronTrigger(jobId) != null); // mechanics: the schedule exists
System.assertEquals(1, [SELECT COUNT() FROM EmailMessage ...]); // behavior: the job's effect
}Assert on the returned jobId, not the name (names can collide).
The two-leg design (checklist): Leg 1 β mechanics: cron trigger exists, scheduled at the right time, schedule returned an ID, no duplicate schedules. Leg 2 β behavior: execute runs (window flush or direct new ReminderJob().execute(null) call) and the effect is asserted (emails/records). If the job calls out (Module 3's nightly sync), leg 2 needs Test.setMock β the mock requirement travels everywhere (Incident 3).
INCIDENT 7 β RETRIEVAL DRILL ANSWERS
- What does
Test.getCronTriggeractually prove? β The schedule row exists β not that the job ran; existence β execution. - When does a scheduled job execute in a test? β Only when scheduled inside the startTest/stopTest window β stopTest flushes it synchronously.
- Why assert on
jobIdinstead of the name? β Names can collide; the returned ID uniquely identifies the trigger. - The two legs of a schedulable test. β Leg 1 mechanics (cron exists, timing, no duplicates); Leg 2 behavior (execute runs + effect asserted).
- Which Module does the mock requirement tie back to? β Module 3 (integrations): callout-mandatory mocking (Incident 3).
INCIDENT 8 β MODEL ANSWER
The diagnosis (three reasons β memorize): (1) No assertion β the test body ended inside the catch; green meant "the runner saw no failure," not "the behavior is correct." (2) Exception-swallowing β the test's own try/catch intercepted the exception; the test cannot distinguish "the code crashed" from "the code handled the failure" β both look identical from inside the catch. (3) Asserting the wrong thing β "an exception was thrown" is the opposite of the retry contract (the code must catch, increment, enqueue). The implicit expectation describes the broken behavior; the retry path was never exercised.
The two correct negative-test patterns (know when each applies):
@isTest(expectedExceptions = SomeException.class)β code that SHOULD throw (validation, guard clauses, malformed input): the annotation IS the assertion β the test fails if no exception is thrown. The throwing pattern.- Behavior assertions β code that should HANDLE a failure (retries, dead-letter, fallback): run it (in the window if async), then assert the handling state. The handling pattern β the retry case is a handling test, not a throwing test.
The corrected retry test (the full Module 3 Incident 8 contract):
@isTest
static void testRetryOnTimeout() {
Test.setMock(HttpCalloutMock.class, new TimeoutMock()); // throws CalloutException
Test.startTest();
BillingSync.run(); // code should CATCH and retry
Test.stopTest();
System.assertEquals(1, [SELECT Retry_Count__c FROM Invoice__c WHERE Id = :inv.Id].Retry_Count__c);
// max-attempt variant (3 failures): assert dead-letter Error_Log__c row + alert
}
// Pattern 2 (code SHOULD throw):
@isTest(expectedExceptions = CalloutException.class)
static void testInvalidInputThrows() {
BillingSync.run(badInput); // must throw β the annotation asserts it
}Related handling test: Database.insert(records, false) β assert the per-record SaveResult errors (the handling pattern applied to DML).
INCIDENT 8 β RETRIEVAL DRILL ANSWERS
- The three reasons the swallowing test is worse than none. β No assertion (green β correct); exception-swallowing (crashed vs handled are indistinguishable); wrong expectation (throwing is the broken behavior for a retry contract).
- Which pattern for code that SHOULD throw β and what does the annotation do? β
@isTest(expectedExceptions=...); it fails the test if no exception is thrown β the annotation IS the assertion. - Which pattern for code that should HANDLE β what is the assertion? β Behavior assertions: the handling state (retry counter, dead-letter, fallback) after the window.
- What does the corrected retry test assert (3 clauses)? β Retry_Count = 1; the retry queueable executed (window flush); dead-letter Error_Log__c + alert on max attempts.
- Why is "test that it throws" the wrong expectation for a retry contract? β The contract says the code must catch and handle β an escaping exception is the broken behavior; the test must assert the handling.
INCIDENT 9 (CAPSTONE) β MODEL ANSWER
1. The 8-pattern recap (the testing contract, one line each):
- I1: Assert behavior, not process β the promised state change, re-queried and exact. Coverage is a byproduct.
- I2: Tests are deterministic β fixed dates, no shared static state;
@TestSetup-reset, mocks for callouts. - I3: Mock every callout β success AND failure; the mock owns the conversation (
Test.setMock+ the four mock classes). - I4: Right-sized fixtures + the window for batches β bulk = code paths, not rows.
- I5: Enqueue inside the window, assert after β
stopTestis the flush. - I6:
runAsfor sharing/FLS β assert the user's view, not the system's. - I7: Schedulables have two legs β mechanics (cron exists) + behavior (job fires, effect asserted).
- I8: Negative tests either expect or assert β
expectedExceptionsfor throwing, handling assertions for retries; never swallow.
2. The audit answers (test strategy):
- (a) What must a test assert? β The state change the code promises, re-queried and exact: the sync marks the row
Synced, the rollup equals the manual SUM, the rep sees only owned records. Process assertions are symptoms, not behavior. - (b) How do you measure testing success? β Behavior coverage per component (success / failure / security / async paths each have a claim), plus suite runtime β a 40-minute suite is a design failure.
- (c) The minimum for a deployable suite? β 75%+ coverage as the floor; behavior tests for every async/security path; no swallowing tests; green + fast.
- (d) Async and security? β Async: the window β enqueue inside, assert after, mocks for callouts. Security:
System.runAs+ user-view assertions + FLS-stripped fields.
3. The new-hire sprint plan (the checklist with Incident mappings):
- The queueable β [I5: window] + [I3: mock, both paths] + [I8: timeoutβretryβdead-letter handling].
- The account search β [I6: runAs sharing β owned vs not] + [I6: FLS stripped].
- The batch rollup β [I4: right-sized + window] + [I1: computed-value vs manual SUM].
- The scheduled reminder β [I7: mechanics leg] + [I7: behavior leg] + [I3: mock if it calls out]. Every checklist ends with: "Which Incident patterns does this component violate if untested?"
4. The three regression tests that MUST ship:
- Queueable success + timeout β proves the sync marks rows
Syncedafter the flush (I5+I3) and the timeout path increments the retry counter and dead-letters on max attempts (I8) β the Module 3 resilience contract. - Search under runAs β proves the rep sees only owned records and FLS strips sensitive fields (I6) β the Module 5 security contract.
- Batch + schedule window β proves the rollup equals the manual SUM (I4+I1) and the scheduled job fires inside the window with its effect asserted (I7) β the automation contracts.
Why "obvious fixes" failed: more tests = volume without the contract; coverage dashboards = reporting, not discipline; one big test class = no structure β the per-component, per-pattern checklist is the structure.
INCIDENT 9 β RETRIEVAL DRILL ANSWERS
- The testing contract in one sentence. β "Every test asserts a behavior claim the code promises β measured on re-queried state, under the user's context, inside the async window, with mocks for every callout, and never a swallowed exception."
- All 8 patterns in order. β I1 behavior-not-process; I2 deterministic; I3 mock both paths; I4 right-sized + window; I5 enqueue-inside-assert-after; I6 runAs; I7 two legs; I8 expect-or-assert.
- The 4 audit answers (compressed). β Assertions = promised state changes; success = behavior covered per component + fast; minimum = 75% floor + behavior-complete + no swallowing; async/security = window + runAs.
- Pattern maps: queueable β 5+3+8; search β 6; batch β 4+1; scheduled β 7+3.
- The three regression tests + proofs. β Queueable success+timeout (synced rows + retry/dead-letter); search runAs (owned-only + FLS); batch+schedule (manual-SUM rollup + job fires).
RAPID-FIRE β MODEL ANSWERS (20)
- The test asserts the fixture, not the behavior β process assertion (T1); re-query the code's result.
- "Coverage is the floor, not the goal" β find the behavior gaps (success/failure/security/async) and assert them; don't farm lines.
- Calendar dependence β the test computes expectations from
today(); fix with a fixed reference date (T3). CalloutExceptionβ the platform enforces the mock rule (T4).- SOAP β
HttpCalloutMockis REST;WebServiceMockis SOAP (T4). - Yes β everything enqueued inside the window, batch
finish()included, runs at stopTest (T5). - The window β enqueue the batch inside
startTest/stopTest; outside, it runs after the test (T6). - The bulk code paths β QueryLocator iteration, chunking/scope, limits inside execute; not row volume (T6).
- The test-running user, system context β sharing/FLS invisible; runAs is the fix (T7).
- Created in the test β real user, standard profile, needed PermissionSets (T7).
- Proves the schedule row exists β the job executes only via the window; assert the effect after stopTest (T7/T5).
- Worse than no test β swallows the failure, asserts nothing; either expect or assert (T8).
- Code that SHOULD throw β validation/guard clauses; the annotation fails the test if nothing throws (T8).
- Handling assertion β the failure was handled; the retry state IS the assertion (T8).
- Governor limits β fresh limits for the window (T5).
- The failure path β retry/dead-letter behavior (T4/T8).
- It asserted the admin's view β the rep's view was never computed; runAs is the verification (T7).
- After β the flush happens at stopTest; assert the post-flush state (T5).
- The enqueue line, not the behavior β coverage counted execution; the sync promise was never asserted (T1).
- Schedule inside the window + assert the effect β the two legs (T7/T5).
INTERLEAVED PRACTICE β MODEL ANSWERS (5)
IP-1 (Integration Γ Testing): The single test: Test.setMock(HttpCalloutMock.class, new TimeoutMock()) β window β 3 failures β assert Retry_Count__c = 2 on the 2nd attempt and the dead-letter Error_Log__c row on the 3rd, plus the alert record. The mock throws CalloutException in respond (timeout simulation); the assertions prove the retry path increments AND the dead-letter path fires β Incidents 3+8.
IP-2 (Security Γ Testing): The fix-proving test: runAs(rep) with an owned account + an account owned by another user β System.assertEquals(1, results.size()) + the owned record's name + System.assertEquals(null, result.SSN__c) (FLS stripped). The pre-fix test asserted the admin's view (system context) β green and meaningless β Incident 6.
IP-3 (Async Γ Testing): Three findings: (1) 50,000-row fixture = volume, not semantics; (2) no startTest/stopTest β the batch ran after the test; (3) assertions compared against fixture pre-set values. Rewrite: 3 parents Γ 4 children β window β assert Rollup__c vs manual SUM (300) β Incident 4.
IP-4 (Automation Γ Testing): The flow's contract ends at its record outcome (the flow test asserts the record state the flow produces); the queueable's contract is the async behavior β its test needs the window (I5) + the callout mock if it calls out (I3) + the failure/retry assertions (I8). The two tests compose: flow outcome test + queueable behavior test.
IP-5 (Order of Execution Γ Testing): Behavior tests asserting the final record state after the full chain (re-queried, exact values β e.g., after trigger + workflow + flow + process all run, the record holds the composed outcome). Process assertions (no exception, one link at a time) miss the chain's composed result β exactly Incident 1's disease at the order-of-execution scale.
THE ONE-CARD KEY (the whole module on one card)
Front: "Testing & Test Classes β the contract." Back (3 lines):
- Assert behavior, not process β the promised state change, re-queried, exact, success + failure paths; coverage is a byproduct. (I1, I8)
- The window + the mock + the user β enqueue inside
startTest, assert afterstopTest(I4/I5/I7);Test.setMockowns every callout, both paths (I3);System.runAsfor sharing/FLS, assert the user's view (I6). - Deterministic or it doesn't exist β fixed dates, reset statics, right-sized fixtures, never a swallowed exception. (I2, I4, I8)
Seal verified. Every model answer above is a deployable claim β say them aloud until they are yours.