function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
John Edwards 3John Edwards 3 

Apex Trigger Test Unable to Access Rollup Data Through SOQL Query

Hello crew, this problem has got me tasting pennies so if anyone could lend some insight I would be eternally grateful. So this is a vastly simplified version of what I am working with (excuse me if this question is poorly formatted, this submission form is a nightmare):

trigger OpportunityTrigger on Opportunity (after insert, after update) {
   <Unimportant Logic Here>
   Set<String> emailSet = OpportunityTriggerHandler.unimportantLogic(Trigger.oldMap, Trigger.NewMap)
   List<Contact> matchingContactsOpenAccounts = OpportunityTriggerHandler.matchingContactsWithAcctStatus(emailSet, 'OPEN');
<More Unimortant Logic>
}

public class OpportunityTriggerHandler {

    public static List<Contact> matchingContactsWithAcctStatus(Set<String> emailSet, 
                                                               String accountStatus)
    {
        List<Contact> matchingContacts = [
            Select
            AccountId,
            Email
            From Contact
            Where Email In :emailSet
            And Account.Billing_Status__c = :accountStatus
            And Account.Original_Close_Date__c != Null       
        ];
        return matchingContacts;
    }
}

@isTest
public class OpportunityTriggerTest {
   @testSetup
       private static void setup()
       {
           <Set Up A Bunch of Stuff>
       }
   
   @isTest
    private static void testWinBackInsertWithNoMatchingAccounts()
    {
        Account beforeOpp = [Select Id from Account Where Name = 'Acct One'];
        Date now = System.today();
        Opportunity o = New Opportunity(
            Name = 'Test Opp',
            AccountId = beforeOpp.Id,
            StageName = 'Booked at DOW',
            CloseDate = now);
        insert o;
        Account afterOpp = [Select Id, Win_Back__c from Account Where Name = 'Acct One'];
        System.assert(afterOpp.Win_Back__c);
    }
}

So the problem I am running into is with the SOQL query in the method matchingContactsWithAcctStatus. This method accepts a list of strings (emails) and an account status and queries for contacts with a matching email and account bill status WHERE the Original_Close_Date__c != Null. 

Original_Close_Date__c is a rollup field that holds the date of the first closed Opportunity on the account. Now here is the fun part. When I functionally test this trigger by creating objects in my dev org, it works fine. If I create mock data in the above test class and call the static function directly in my test class it works fine. However, in the above example, when I insert a mock Opportunity to fire the trigger IN A TEST CLASS the SOQL function is no longer able to access the value in that rollup field. It always returns Null value when calling the SOQL query from within that function. I literally invoked the trigger in the test class and ran it side by side calling the method with the same params and watched as they returned different data.

My initial reaction is to just stop using rollup functions in Apex triggers if they can't reliably be tested. I can just throw in another function that determines whether or not that field is null but this seems so... dumb. Am I missing anything? 

Thanks!
Abdul KhatriAbdul Khatri
Hi John,

Can you make sure the Opportunity Status that Rollup is in matching in the criteria with the status you are using in the test class when creating opportunity?

You are actually right it is dumb to use another any logic in order to handle out of box functionality.

Regards,
Andrew GAndrew G
I would have a look at playing with Test.startTest() and Test.stopTest();

Apart from defining the limits on the test run, i have found that they seem to help complete results in test classes, especially when some sort of calculation is required.

So looking at that test method:
@isTest
    private static void testWinBackInsertWithNoMatchingAccounts()
    {
        Account beforeOpp = [Select Id from Account Where Name = 'Acct One'];
        Date now = System.today();
Test.startTest();
        Opportunity o = New Opportunity(
            Name = 'Test Opp',
            AccountId = beforeOpp.Id,
            StageName = 'Booked at DOW',
            CloseDate = now);
        insert o;
Test.stopTest();
        Account afterOpp = [Select Id, Win_Back__c,Original_Close_Date__c  from Account Where Name = 'Acct One'];
        System.assert(afterOpp.Win_Back__c);
        System.debug(afterOpp.Original_Close_Date__c );
    }

i believe the startTest/stopTest relates somehow to this:

All asynchronous calls made after the startTest method are collected by the system. When stopTest is executed, all asynchronous processes are run synchronously.

reference:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_tools_start_stop_test.htm

Perhaps the rollup is an asynchronous call that needs to be forced to complete

regards
Andrew