Advanced 30 min read

Test Data Factories

By the end of this lesson, you'll be able to:

  • Extract repeated test-data setup into a reusable factory method
  • Explain why duplicated setup code across test methods is worth refactoring
  • Apply Module 12/17/22/23's refactoring habit specifically to test code

Prerequisites: "Testing Triggers: Bulk and Edge Cases"

Spotting duplication across test methods

@isTest
static void test1() {
    Account acc = new Account(Name = 'Test Account', Industry = 'Technology');
    insert acc;
    // ...
}

@isTest
static void test2() {
    Account acc = new Account(Name = 'Test Account', Industry = 'Technology');
    insert acc;
    // ...
}
  1. @isTest — marks the first test method.
  2. static void test1() { — one test.
  3. Account acc = new Account(Name = 'Test Account', Industry = 'Technology'); — every test method needing a valid Account repeats the exact same setup.
  4. insert acc; — saves it.
  5. // ... — the rest of this test.
  6. } — closes this test method.
  7. (blank line)
  8. @isTest — marks a second test method.
  9. static void test2() { — a different test.
  10. Account acc = new Account(Name = 'Test Account', Industry = 'Technology'); — the exact same setup, duplicated.
  11. insert acc; — saves it.
  12. // ... — the rest of this test.
  13. } — closes this test method — the same duplication problem Modules 12, 17, 22, and 23 each closed out by extracting a shared private method, now showing up in test code specifically.

Extracting a factory method

@isTest
private class AccountRollupServiceTest {
    private static Account createTestAccount() {
        Account acc = new Account(Name = 'Test Account', Industry = 'Technology');
        insert acc;
        return acc;
    }

    @isTest
    static void test1() {
        Account acc = createTestAccount();
        // ...
    }

    @isTest
    static void test2() {
        Account acc = createTestAccount();
        // ...
    }
}
  1. @isTest — marks the class.
  2. private class AccountRollupServiceTest { — the class.
  3. private static Account createTestAccount() { — private static — callable directly from any @isTest static method in the same class, exactly like the trigger handler's private helpers from Module 22.
  4. Account acc = new Account(Name = 'Test Account', Industry = 'Technology'); — the one, now-shared setup.
  5. insert acc; — saves it.
  6. return acc; — hands it back.
  7. } — closes the factory method.
  8. (blank line)
  9. @isTest — marks the first test.
  10. static void test1() { — a test.
  11. Account acc = createTestAccount(); — delegates instead of repeating the setup.
  12. // ... — the rest of this test.
  13. } — closes this test.
  14. (blank line)
  15. @isTest — marks the second test.
  16. static void test2() { — a different test.
  17. Account acc = createTestAccount(); — the same shared factory.
  18. // ... — the rest of this test.
  19. } — closes this test.
  20. } — closes the class.

Any future change to what a "valid test Account" needs happens in exactly one place.

A shared factory class for reuse across multiple test classes

@isTest
public class TestDataFactory {
    public static Account createAccount(String name) {
        Account acc = new Account(Name = name, Industry = 'Technology');
        insert acc;
        return acc;
    }

    public static Book__c createBook(String title) {
        return new Book__c(Title__c = title, ISBN__c = '000-0-000-00000-0', Is_Checked_Out__c = false);
    }
}

// used from any test class:
Account acc = TestDataFactory.createAccount('Riverbend Farms');
  1. @isTest — marks the class as test-only, but public so it can be called from other test classes.
  2. public class TestDataFactory { — for data patterns reused across multiple test classes, not just within one.
  3. public static Account createAccount(String name) { — a reusable factory method.
  4. Account acc = new Account(Name = name, Industry = 'Technology'); — builds it.
  5. insert acc; — saves it.
  6. return acc; — hands it back.
  7. } — closes the method.
  8. (blank line)
  9. public static Book__c createBook(String title) { — a second factory method, for a different object.
  10. return new Book__c(Title__c = title, ISBN__c = '000-0-000-00000-0', Is_Checked_Out__c = false); — builds and returns it directly.
  11. } — closes the method.
  12. } — closes the class.
  13. (blank line)
  14. // used from any test class: — the label for the usage example.
  15. Account acc = TestDataFactory.createAccount('Riverbend Farms'); — avoids duplicating the same setup logic across every test file in the org — the natural next step once a single class's private helper isn't enough.

Exercise

Extract a private static createTestBook() factory method that inserts and returns a valid Book__c, then use it in a test method.

Show hint

private static Book__c createTestBook() { ...; insert book; return book; }

APEX

Test Data Factories Quiz

1. Why extract repeated test-data setup into a factory method?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

Just like production code, test code accumulates duplication — a test data factory extracts the repeated "build a valid test record" logic into one reusable method, exactly the refactoring instinct from every project module's closing lesson.