mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-07-30 03:09:50 +08:00
* Migrating Core Salesforce Skills * Updating pr comments * updat reference * Updating a skill * Migrating Datacloud skills * Migrating Industries cloud skills * Validating - skills fixing --------- Co-authored-by: Sandip Kumar Yadav <sandipkumar.yadav+sfemu@salesforce.com>
7.6 KiB
7.6 KiB
Test Data Factory Usage
How to use and customize the test data factory templates.
Basic Factory Pattern
Account Factory
public class TestDataFactory_Account {
// Basic creation - inserted
public static List<Account> create(Integer count) {
return create(count, true);
}
// Control insertion
public static List<Account> create(Integer count, Boolean doInsert) {
List<Account> records = new List<Account>();
for (Integer i = 0; i < count; i++) {
records.add(new Account(
Name = 'Test Account ' + i,
Industry = 'Technology'
));
}
if (doInsert) {
insert records;
}
return records;
}
}
Usage Examples
// Create 10 accounts (inserted)
List<Account> accounts = TestDataFactory_Account.create(10);
// Create 10 accounts (not inserted - for customization)
List<Account> accounts = TestDataFactory_Account.create(10, false);
accounts[0].AnnualRevenue = 1000000;
accounts[1].Rating = 'Hot';
insert accounts;
Factory with Variations
Industry Variations
public static List<Account> createWithVariedIndustries(Integer count) {
List<Account> records = new List<Account>();
List<String> industries = new List<String>{
'Technology', 'Healthcare', 'Finance', 'Manufacturing', 'Retail'
};
for (Integer i = 0; i < count; i++) {
records.add(new Account(
Name = 'Test Account ' + i,
Industry = industries[Math.mod(i, industries.size())]
));
}
insert records;
return records;
}
Revenue Tiers
public static List<Account> createWithRevenueTiers(Integer count) {
List<Account> records = new List<Account>();
List<Decimal> tiers = new List<Decimal>{
100000, 500000, 1000000, 5000000, 10000000
};
for (Integer i = 0; i < count; i++) {
records.add(new Account(
Name = 'Test Account ' + i,
AnnualRevenue = tiers[Math.mod(i, tiers.size())]
));
}
insert records;
return records;
}
Factory with Relationships
Contact Factory with Account
public class TestDataFactory_Contact {
// Create contacts for existing accounts
public static List<Contact> createForAccounts(Set<Id> accountIds, Integer perAccount) {
List<Contact> contacts = new List<Contact>();
Integer i = 0;
for (Id accId : accountIds) {
for (Integer j = 0; j < perAccount; j++) {
contacts.add(new Contact(
FirstName = 'Test',
LastName = 'Contact ' + i,
AccountId = accId,
Email = 'test' + i + '@example.com'
));
i++;
}
}
insert contacts;
return contacts;
}
}
Usage
// Create 10 accounts with 3 contacts each
List<Account> accounts = TestDataFactory_Account.create(10);
Set<Id> accountIds = new Map<Id, Account>(accounts).keySet();
List<Contact> contacts = TestDataFactory_Contact.createForAccounts(accountIds, 3);
// Total: 10 accounts + 30 contacts
Hierarchy Factory
Complete Hierarchy in One Call
public class TestDataFactory_Hierarchy {
public class HierarchyResult {
public List<Account> accounts;
public List<Contact> contacts;
public List<Opportunity> opportunities;
}
public static HierarchyResult create(
Integer accountCount,
Integer contactsPerAccount,
Integer oppsPerAccount
) {
HierarchyResult result = new HierarchyResult();
// Create accounts
result.accounts = TestDataFactory_Account.create(accountCount);
Set<Id> accountIds = new Map<Id, Account>(result.accounts).keySet();
// Create contacts
result.contacts = TestDataFactory_Contact.createForAccounts(
accountIds, contactsPerAccount
);
// Create opportunities
result.opportunities = TestDataFactory_Opportunity.createForAccounts(
accountIds, oppsPerAccount
);
return result;
}
}
Usage
// Create complete test hierarchy
HierarchyResult data = TestDataFactory_Hierarchy.create(
10, // accounts
3, // contacts per account
2 // opportunities per account
);
// Total: 10 accounts + 30 contacts + 20 opportunities
System.debug('Accounts: ' + data.accounts.size());
System.debug('Contacts: ' + data.contacts.size());
System.debug('Opportunities: ' + data.opportunities.size());
Edge Case Factories
Boundary Values
public static Account createWithMinValues() {
return new Account(
Name = 'A' // Minimum name length
);
}
public static Account createWithMaxValues() {
return new Account(
Name = 'X'.repeat(255), // Maximum name length
Description = 'Y'.repeat(32000) // Maximum description
);
}
Special Characters
public static Account createWithSpecialCharacters() {
return new Account(
Name = 'Test & "Special" <Characters> \'Quotes\''
);
}
Null/Empty Values
public static List<Account> createWithNullableFields(Integer count) {
List<Account> records = new List<Account>();
for (Integer i = 0; i < count; i++) {
Account acc = new Account(Name = 'Test ' + i);
// Leave optional fields null
// acc.Industry = null;
// acc.AnnualRevenue = null;
records.add(acc);
}
insert records;
return records;
}
Using Factories for Testing
Trigger Test Example
@isTest
public class AccountTriggerTest {
@isTest
static void testBulkInsert() {
// Setup - 201 records to test batch boundaries
Test.startTest();
List<Account> accounts = TestDataFactory_Account.create(201);
Test.stopTest();
// Verify trigger logic executed
List<Account> results = [
SELECT Id, Custom_Field__c
FROM Account
WHERE Id IN :accounts
];
for (Account acc : results) {
System.assertNotEquals(null, acc.Custom_Field__c,
'Trigger should have set Custom_Field__c');
}
}
@isTest
static void testWithRelatedRecords() {
// Setup hierarchy
HierarchyResult data = TestDataFactory_Hierarchy.create(5, 2, 1);
Test.startTest();
// Test logic that involves relationships
MyClass.processAccountsWithContacts(data.accounts);
Test.stopTest();
// Verify results
}
}
Flow Test Example
@isTest
static void testRecordTriggeredFlow() {
// Create data that matches flow entry criteria
List<Account> accounts = TestDataFactory_Account.create(10, false);
for (Account acc : accounts) {
acc.Industry = 'Technology'; // Matches flow filter
acc.AnnualRevenue = 1000000; // Triggers flow action
}
Test.startTest();
insert accounts; // Flow fires on insert
Test.stopTest();
// Verify flow results
List<Task> tasks = [SELECT Id FROM Task WHERE WhatId IN :accounts];
System.assertEquals(10, tasks.size(), 'Flow should create task for each account');
}
Best Practices
- Always return inserted records - Caller may need IDs
- Provide doInsert parameter - Allow customization before insert
- Use bulk patterns - Single DML for multiple records
- Handle required fields - Prevent validation errors
- Use unique values - Avoid duplicate rule violations
- Track IDs for cleanup - Enable proper test isolation