Skip to main content
added 1187 characters in body
Source Link
Adrian Larson
  • 151.4k
  • 38
  • 247
  • 431

Fun fact, if you adopt the latter pattern, you can implement a library like Selector to do the filtering for you.

public with sharing class AccountService
{
    public static Select.Filter isFlagged()
    {
        return Select.Field.isEqual(Account.Some_Flag__c, true);
    }
    public static void validateFlaggedAccounts(List<Account> flaggedAccounts)
    {
        for (Account flaggedAccount : flaggedAccounts)
            flaggedAccount.addError('message');
    }
}

Then in your trigger you can just do:

AccountServices.validateFlaggedAccounts(
    AccountServices.isFlagged().filter(trigger.new, trigger.oldMap)
);

One huge advantage of this pattern is it's way easier to test. You can test the positive/negative filter cases very easily, then test your action completely independently. Separation of concerns, ftw!

static final Integer RECORD_COUNT = Limits.getLimitQueries() + 1;
static testMethod void testIsFlagged_Positive()
{
    List<Account> accounts = new List<Account>();
    for (Integer i = 0; i < RECORD_COUNT; i++)
        accounts.add(new Account(Some_Flag__c=true));
    
    Test.startTest();
        List<Account> results = AccountService.isFlagged().filter(accounts);
    Test.stopTest();
    
    system.assertEquals(RECORD_COUNT, results.size(), 'message');
}
static testMethod void testIsFlagged_Negative()
{
    List<Account> accounts = new List<Account>();
    for (Integer i = 0; i < RECORD_COUNT; i++)
        accounts.add(new Account(Some_Flag__c=false));
    
    Test.startTest();
        List<Account> results = AccountService.isFlagged().filter(accounts);
    Test.stopTest();
    
    system.assertEquals(0, results.size(), 'message');
}

Fun fact, if you adopt the latter pattern, you can implement a library like Selector to do the filtering for you.

public with sharing class AccountService
{
    public static Select.Filter isFlagged()
    {
        return Select.Field.isEqual(Account.Some_Flag__c, true);
    }
    public static void validateFlaggedAccounts(List<Account> flaggedAccounts)
    {
        for (Account flaggedAccount : flaggedAccounts)
            flaggedAccount.addError('message');
    }
}

Then in your trigger you can just do:

AccountServices.validateFlaggedAccounts(
    AccountServices.isFlagged().filter(trigger.new, trigger.oldMap)
);

Fun fact, if you adopt the latter pattern, you can implement a library like Selector to do the filtering for you.

public with sharing class AccountService
{
    public static Select.Filter isFlagged()
    {
        return Select.Field.isEqual(Account.Some_Flag__c, true);
    }
    public static void validateFlaggedAccounts(List<Account> flaggedAccounts)
    {
        for (Account flaggedAccount : flaggedAccounts)
            flaggedAccount.addError('message');
    }
}

Then in your trigger you can just do:

AccountServices.validateFlaggedAccounts(
    AccountServices.isFlagged().filter(trigger.new, trigger.oldMap)
);

One huge advantage of this pattern is it's way easier to test. You can test the positive/negative filter cases very easily, then test your action completely independently. Separation of concerns, ftw!

static final Integer RECORD_COUNT = Limits.getLimitQueries() + 1;
static testMethod void testIsFlagged_Positive()
{
    List<Account> accounts = new List<Account>();
    for (Integer i = 0; i < RECORD_COUNT; i++)
        accounts.add(new Account(Some_Flag__c=true));
    
    Test.startTest();
        List<Account> results = AccountService.isFlagged().filter(accounts);
    Test.stopTest();
    
    system.assertEquals(RECORD_COUNT, results.size(), 'message');
}
static testMethod void testIsFlagged_Negative()
{
    List<Account> accounts = new List<Account>();
    for (Integer i = 0; i < RECORD_COUNT; i++)
        accounts.add(new Account(Some_Flag__c=false));
    
    Test.startTest();
        List<Account> results = AccountService.isFlagged().filter(accounts);
    Test.stopTest();
    
    system.assertEquals(0, results.size(), 'message');
}
Source Link
Adrian Larson
  • 151.4k
  • 38
  • 247
  • 431

Fun fact, if you adopt the latter pattern, you can implement a library like Selector to do the filtering for you.

public with sharing class AccountService
{
    public static Select.Filter isFlagged()
    {
        return Select.Field.isEqual(Account.Some_Flag__c, true);
    }
    public static void validateFlaggedAccounts(List<Account> flaggedAccounts)
    {
        for (Account flaggedAccount : flaggedAccounts)
            flaggedAccount.addError('message');
    }
}

Then in your trigger you can just do:

AccountServices.validateFlaggedAccounts(
    AccountServices.isFlagged().filter(trigger.new, trigger.oldMap)
);