Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
clientell-ai avatar

Sf Test

  • 42 installs
  • 12 repo stars
  • Updated July 14, 2026
  • clientell-ai/salesforce-skills

Sf-test is an agent skill that supplies Apex test pattern examples for async code including @future and batch jobs.

About

Sf-test is an agent skill that provides a patterns reference for Salesforce Apex testing with full, compilable examples. Solo builders and small teams shipping on Salesforce use it when implementing @future handlers, batch jobs, and similar asynchronous Apex and need tests that actually exercise async boundaries via Test.startTest() and Test.stopTest(). The readme walks through realistic classes and matching @IsTest classes, including constraints such as batch execute scope in tests and the single executeBatch call per method. Point your agent at this skill during Ship testing work to avoid hollow tests that never flush futures or batches, and to standardize assertion style. It is pattern documentation rather than a test runner or CI integration.

  • Complete compilable examples for major Apex test patterns in one reference
  • @future methods run synchronously inside Test.startTest() / Test.stopTest() boundaries in tests
  • Batch Apex executes between startTest and stopTest with documented 200-record execute limit in test context
  • Only one Database.executeBatch call allowed per test method
  • Examples use modern Assert.areEqual style assertions with descriptive messages

Sf Test by the numbers

  • 42 all-time installs (skills.sh)
  • Ranked #1,262 of 2,153 Testing & QA skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/clientell-ai/salesforce-skills --skill sf-test

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs42
repo stars12
Security audit3 / 3 scanners passed
Last updatedJuly 14, 2026
Repositoryclientell-ai/salesforce-skills

What it does

Write compilable Salesforce Apex tests for @future, batch, and related async patterns using Test.startTest and Test.stopTest correctly.

Who is it for?

Best when you're writing or reviewing Apex tests before deploy or package submission.

Skip if: Non-Salesforce stacks, pure Lightning Web Component Jest tests without Apex, or orgs that forbid pattern copy without org-specific data factories.

When should I use this skill?

Writing or fixing Apex tests for @future, batch, or related async Salesforce patterns.

What you get

You get copy-ready @IsTest classes that respect Salesforce test semantics for futures and batch jobs with clear assertions.

  • Compilable @IsTest class for async Apex
  • Documented test pattern snippets for batch and @future

By the numbers

  • Batch execute() receives at most 200 records per batch in test context
  • Only one Database.executeBatch call allowed per Apex test method

Files

SKILL.mdMarkdownGitHub ↗

Apex Test Class Generator

You are a Salesforce test class specialist. Generate comprehensive test classes that achieve 85%+ code coverage with meaningful assertions.

Test Class Structure

Required Pattern

@IsTest
private class MyClassTest {

    @TestSetup
    static void makeData() {
        // Use TestFactory for all record creation
        List<Account> accounts = TestDataFactory.createAccounts(200);
        insert accounts;

        List<Contact> contacts = TestDataFactory.createContacts(accounts);
        insert contacts;
    }

    @IsTest
    static void testMethodName_positiveScenario() {
        // Arrange
        List<Account> accounts = [SELECT Id, Name FROM Account WITH USER_MODE];

        // Act
        Test.startTest();
        MyClass.myMethod(accounts);
        Test.stopTest();

        // Assert
        List<Account> results = [SELECT Id, Status__c FROM Account WITH USER_MODE];
        System.assertEquals(200, results.size(), 'All accounts should be processed');
        for (Account acc : results) {
            System.assertNotEquals(null, acc.Status__c, 'Status should be set');
        }
    }
}

Test Scenarios (generate ALL of these)

1. Positive tests: Happy path with valid data 2. Negative tests: Invalid data, null inputs, empty lists 3. Bulk tests: 200+ records to verify bulkification 4. Permission tests: Test with restricted user profile 5. Boundary tests: Edge cases (0 records, 1 record, max records)

Permission Testing Pattern

@IsTest
static void testMethod_restrictedUser() {
    User restrictedUser = TestDataFactory.createStandardUser();
    insert restrictedUser;

    System.runAs(restrictedUser) {
        Test.startTest();
        try {
            MyClass.myMethod(testData);
            System.assert(false, 'Should have thrown exception');
        } catch (SecurityException e) {
            System.assert(e.getMessage().contains('access'),
                'Should throw security exception');
        }
        Test.stopTest();
    }
}

Callout Mock Pattern

@IsTest
private class MyCalloutClassTest {

    private class MockHttpResponse implements HttpCalloutMock {
        private Integer statusCode;
        private String body;

        MockHttpResponse(Integer statusCode, String body) {
            this.statusCode = statusCode;
            this.body = body;
        }

        public HttpResponse respond(HttpRequest req) {
            HttpResponse res = new HttpResponse();
            res.setStatusCode(this.statusCode);
            res.setBody(this.body);
            return res;
        }
    }

    @IsTest
    static void testCallout_success() {
        Test.setMock(HttpCalloutMock.class, new MockHttpResponse(200, '{"status":"ok"}'));

        Test.startTest();
        String result = MyCalloutClass.makeCallout();
        Test.stopTest();

        System.assertEquals('ok', result, 'Should return success status');
    }

    @IsTest
    static void testCallout_failure() {
        Test.setMock(HttpCalloutMock.class, new MockHttpResponse(500, '{"error":"fail"}'));

        Test.startTest();
        try {
            MyCalloutClass.makeCallout();
            System.assert(false, 'Should throw on 500');
        } catch (CalloutException e) {
            System.assert(true, 'Exception expected on server error');
        }
        Test.stopTest();
    }
}

Rules

  • NEVER hardcode record IDs — always query or create in @TestSetup
  • ALWAYS use Test.startTest() and Test.stopTest() to reset governor limits
  • ALWAYS use System.assertEquals / System.assertNotEquals with descriptive messages
  • ALWAYS test with 200 records minimum for bulk scenarios
  • Use @TestVisible on private methods/variables instead of making them public
  • Create a TestDataFactory class if one doesn't exist
  • NEVER use SeeAllData=true unless testing specific platform features
  • Test both synchronous and asynchronous paths (future, queueable, batch)

TestDataFactory Pattern

@IsTest
public class TestDataFactory {

    public static List<Account> createAccounts(Integer count) {
        List<Account> accounts = new List<Account>();
        for (Integer i = 0; i < count; i++) {
            accounts.add(new Account(
                Name = 'Test Account ' + i
            ));
        }
        return accounts;
    }

    public static User createStandardUser() {
        Profile p = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1];
        return new User(
            FirstName = 'Test',
            LastName = 'User',
            Email = 'testuser@example.com',
            Username = 'testuser' + DateTime.now().getTime() + '@example.com',
            Alias = 'tuser',
            TimeZoneSidKey = 'America/Los_Angeles',
            LocaleSidKey = 'en_US',
            EmailEncodingKey = 'UTF-8',
            ProfileId = p.Id,
            LanguageLocaleKey = 'en_US'
        );
    }
}

Async Testing Patterns

  • @future: Runs after Test.stopTest() — assert side effects after stopTest
  • Batch: Call Database.executeBatch() between Test.startTest() / Test.stopTest()
  • Queueable: Call System.enqueueJob() between startTest/stopTest — chaining limited to depth 1 in test
  • Schedulable: Call System.schedule() between startTest/stopTest — assert CronTrigger afterward

Platform Event & CDC Testing

  • Platform Events: Call Test.getEventBus().deliver() after publishing to force synchronous delivery
  • Change Data Capture: Call Test.enableChangeDataCapture() in test setup, then Test.getEventBus().deliver() after DML

Stub API (Dependency Injection)

Use System.StubProvider interface + Test.createStub() to mock dependencies without hitting the database.

Test.loadData()

Load bulk test data from CSV in a Static Resource: Test.loadData(Account.sObjectType, 'TestAccounts')

Mixed DML Workaround

Use System.runAs() to separate setup object DML (User, Profile) from non-setup objects in the same test.

Special Object Testing

  • Use Test.getStandardPricebookId() for Product2/PricebookEntry tests
  • Use RestContext.request = new RestRequest() for @RestResource endpoint tests

Gotchas

  • @TestSetup data is shared (NOT isolated) across test methods — each method gets a copy that resets
  • SeeAllData=true exposes production data — almost never use it
  • Future/Batch/Queueable execute AFTER Test.stopTest(), not during
  • Callout mock (Test.setMock()) must be registered BEFORE Test.startTest()
  • Platform Event ordering is NOT guaranteed in tests
  • Test.startTest() / Test.stopTest() can only be called ONCE per test method
  • Batch Apex finish() method also runs after Test.stopTest()
  • Mixed DML throws MIXED_DML_OPERATION — use System.runAs() to workaround

Workflow

1. Read the class under test using Read/Glob tools 2. Identify all public/global methods and code paths 3. Check if TestDataFactory exists; create if not 4. Generate test class with all scenario types 5. Run tests: sf apex run test -n MyClassTest --synchronous --code-coverage 6. Report coverage and fix any failures

References

  • Test Patterns — async testing, Platform Events, CDC, Stub API, REST endpoints, mixed DML, Flow test coverage
  • Governor Limits — per-transaction limits for test context

Related skills

How it compares

Apex-specific async test cookbook, not generic Jest or Playwright end-to-end guidance.

FAQ

Who is sf-test for?

and small-team Salesforce developers who need reliable Apex unit tests for asynchronous and batch code paths.

When should I use sf-test?

During Ship testing when adding @future or batch Apex, fixing flaky async tests, or onboarding an agent to Salesforce test idioms.

Is sf-test safe to install?

The skill is reference text only; deploying generated Apex still runs in your org—review the Security Audits panel on this Prism page and your own code review process.

Testing & QAbackendtesting

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.