+ Start a Discussion
Antone KomAntone Kom 

Update Record Quick Action invoked by Batch Apex Class - Test class is failing to recognize that the records were updated, assert is failing.

Hello,

I am running into a strange issue - I have created a Record Update QuickAction on Contact object, which we have added on page layouts for users to be able to anonymize the contact record (for GDPR compliance purposes).  This QuickAction uses Predefined Field Values to remove / obfuscate data on certain contact fields that contain personal info (Name, Email, Phone #, etc.)  The action is working fine when invoked on a single record from the UI.

As part of our Sandbox refresh strategy, I am trying to invoke the same QuickAction via apex code to anonymize ALL contacts as a post-refresh task (Apex class that implements SandboxPostCopy interface).  Since it should run on all records, I am invoking it from a Batchable class.  

What I am running into is that in my test class, it appears in debug logs that invoking the QuickAction on the batch of records is successful, but when I re-query those records to do an assert to make sure they were updated, the query shows that the records have NOT been updated by the Quick Action.

Here is some sample code to illustrate:
 
global class SandboxBuild implements SandboxPostCopy{
	final String CLASSNAME = '\n\n**** SandboxBuild.METHODNAME()';
	global void runApexClass(SandboxContext context){
		final string METHODNAME = CLASSNAME.replace('METHODNAME','runApexClass');
		system.debug(LoggingLevel.INFO, METHODNAME.replace('**** ', '**** Inside '));

        SandboxBuildHelper sbh = new SandboxBuildHelper();
		sbh.anonymizeContacts();
	}
}
public class SandboxBuildHelper {

    public void anonymizeContacts() { 
        // Query for selecting the contacts to anonymize - in this case ALL contacts
        String query = 'SELECT Id FROM Contact Limit 5';
        
        // Invoke the batch job.
        BatchGDPRAnonymizeContacts bAnon = new BatchGDPRAnonymizeContacts(query);
        Id batchprocessid = Database.executeBatch(bAnon);
        System.debug('Returned batch process ID: ' + batchProcessId);
    }

}
 
global class BatchGDPRAnonymizeContacts implements Database.Batchable<sObject> {
	
	global final String query;
	
	global BatchGDPRAnonymizeContacts(String q) {
		query=q;
	}
		
	global Database.QueryLocator start(Database.BatchableContext BC) {
		return Database.getQueryLocator(query);
	}

   	global void execute(Database.BatchableContext BC, List<sObject> scope) {
		
        List<QuickAction.QuickActionRequest> reqs = new List<QuickAction.QuickActionRequest>();
		List<QuickAction.QuickActionResult> results = new List<QuickAction.QuickActionResult>();
        for(sObject s : scope){
			Contact c = (Contact)s;
			system.debug('Contact: '+ c.FirstName+' '+c.LastName+' - '+c.Email+' - '+c.Phone);
			QuickAction.QuickActionRequest req = new QuickAction.QuickActionRequest();
        	req.quickActionName = Schema.Contact.QuickAction.GDPR_Anonymize_Contact;
			req.record = c;
        	reqs.add(req);
		}
		results = QuickAction.performQuickActions(reqs);
		for(QuickAction.QuickActionResult r: results){
			system.debug('getIds(): '+r.getIds());
			system.debug('getSuccessMessage(): '+r.getSuccessMessage());
			system.debug('isCreated(): '+r.isCreated());
			system.debug('isSuccess(): '+r.isSuccess());
			system.debug('getErrors(): '+r.getErrors());
		}
	}
	
	global void finish(Database.BatchableContext BC){
		// Get the ID of the AsyncApexJob representing this batch job
		// from Database.BatchableContext.
		// Query the AsyncApexJob object to retrieve the current job's information.
		AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
			TotalJobItems, CreatedBy.Email
			FROM AsyncApexJob WHERE Id = :BC.getJobId()];

		system.debug('Apex BatchGDPRAnonymizeContacts ' + a.Status);
		system.debug('The batch Apex job processed ' + a.TotalJobItems + ' batches with '+ a.NumberOfErrors + ' failures.');
	}
	
}
 
@isTest
private class BatchGDPRAnonymizeContacts_Test {
    
    @isTest static void testbatch() {
        // create 200 test contacts - this simulates one execute.
        // Important - the Salesforce.com test framework only allows you to
        // test one execute
        List <Contact> cList = new List<Contact>();
        Integer numContacts = 5;
            for(integer i = 0; i<numContacts; i++){
                Contact c = new Contact (FirstName='test', LastName='Contact'+i, Email='test'+i+'@test.com', Phone='+1208555000'+i);
                cList.add(c);
            }
        
        insert cList;
        
        Test.StartTest();
        String query = 'SELECT ID, FirstName, LastName, Email, Phone ' +
                    'FROM Contact ' +
                    ' LIMIT ' + numContacts;
        BatchGDPRAnonymizeContacts batch = new BatchGDPRAnonymizeContacts(query);
        
        ID batchprocessid = Database.executeBatch(batch, 50);
        Test.StopTest();
        List<Contact> cListAnon = [Select Id, FirstName, LastName, Email, Phone from Contact];
        system.debug('cListAnon: ' + cListAnon);
        
        System.AssertEquals( numContacts, database.countquery('SELECT COUNT() FROM Contact WHERE FirstName=\'ANONYMOUS\''));
        
    }
}

Exceprts of DEBUG output when running the Apex Test:
 
12:50:12.990 (4209501390)|CODE_UNIT_STARTED|[EXTERNAL]|01pq0000000ajd6|BatchGDPRAnonymizeContacts
12:50:12.990 (4215187082)|SOQL_EXECUTE_BEGIN|[11]|Aggregations:0|SELECT ID, FirstName, LastName, Email, Phone FROM Contact  
12:50:12.990 (4299212112)|SOQL_EXECUTE_END|[11]|Rows:5
12:50:12.990 (4325480890)|CODE_UNIT_FINISHED|BatchGDPRAnonymizeContacts
12:50:12.990 (4326373234)|CODE_UNIT_STARTED|[EXTERNAL]|01pq0000000ajd6|BatchGDPRAnonymizeContacts
12:50:12.990 (4347406438)|CODE_UNIT_STARTED|[EXTERNAL]|01pq0000000ajd6|BatchGDPRAnonymizeContacts
12:50:12.990 (4348454925)|USER_DEBUG|[20]|DEBUG|Contact: test Contact0 - test0@test.com - +12085550000
12:50:12.990 (4348661312)|USER_DEBUG|[20]|DEBUG|Contact: test Contact1 - test1@test.com - +12085550001
12:50:12.990 (4348743660)|USER_DEBUG|[20]|DEBUG|Contact: test Contact2 - test2@test.com - +12085550002
12:50:12.990 (4348811920)|USER_DEBUG|[20]|DEBUG|Contact: test Contact3 - test3@test.com - +12085550003
12:50:12.990 (4348877642)|USER_DEBUG|[20]|DEBUG|Contact: test Contact4 - test4@test.com - +12085550004
12:50:12.990 (4349377319)|DML_BEGIN|[27]|Op:PerformQuickAction|Type:QuickActionResult|Rows:5
.
.
.
.
12:50:12.990 (4681351512)|DML_END|[27]
12:50:12.990 (4681899567)|USER_DEBUG|[29]|DEBUG|getIds(): (003q000000w1HK0AAM)
12:50:12.990 (4681941852)|USER_DEBUG|[30]|DEBUG|getSuccessMessage(): Contact details successfully anonymized.
12:50:12.990 (4681982207)|USER_DEBUG|[31]|DEBUG|isCreated(): false
12:50:12.990 (4682015050)|USER_DEBUG|[32]|DEBUG|isSuccess(): true
12:50:12.990 (4682105172)|USER_DEBUG|[33]|DEBUG|getErrors(): ()
12:50:12.990 (4682171498)|USER_DEBUG|[29]|DEBUG|getIds(): (003q000000w1HK1AAM)
12:50:12.990 (4682187044)|USER_DEBUG|[30]|DEBUG|getSuccessMessage(): Contact details successfully anonymized.
12:50:12.990 (4682204942)|USER_DEBUG|[31]|DEBUG|isCreated(): false
12:50:12.990 (4682229456)|USER_DEBUG|[32]|DEBUG|isSuccess(): true
12:50:12.990 (4682260353)|USER_DEBUG|[33]|DEBUG|getErrors(): ()
12:50:12.990 (4682313526)|USER_DEBUG|[29]|DEBUG|getIds(): (003q000000w1HK2AAM)
12:50:12.990 (4682328104)|USER_DEBUG|[30]|DEBUG|getSuccessMessage(): Contact details successfully anonymized.
12:50:12.990 (4682345912)|USER_DEBUG|[31]|DEBUG|isCreated(): false
12:50:12.990 (4682361731)|USER_DEBUG|[32]|DEBUG|isSuccess(): true
12:50:12.990 (4682389503)|USER_DEBUG|[33]|DEBUG|getErrors(): ()
12:50:12.990 (4682436899)|USER_DEBUG|[29]|DEBUG|getIds(): (003q000000w1HK3AAM)
12:50:12.990 (4682450390)|USER_DEBUG|[30]|DEBUG|getSuccessMessage(): Contact details successfully anonymized.
12:50:12.990 (4682467749)|USER_DEBUG|[31]|DEBUG|isCreated(): false
12:50:12.990 (4682483932)|USER_DEBUG|[32]|DEBUG|isSuccess(): true
12:50:12.990 (4682510753)|USER_DEBUG|[33]|DEBUG|getErrors(): ()
12:50:12.990 (4682555396)|USER_DEBUG|[29]|DEBUG|getIds(): (003q000000w1HK4AAM)
12:50:12.990 (4682568987)|USER_DEBUG|[30]|DEBUG|getSuccessMessage(): Contact details successfully anonymized.
12:50:12.990 (4682585831)|USER_DEBUG|[31]|DEBUG|isCreated(): false
12:50:12.990 (4682602455)|USER_DEBUG|[32]|DEBUG|isSuccess(): true
12:50:12.990 (4682629221)|USER_DEBUG|[33]|DEBUG|getErrors(): ()
12:50:12.990 (4682654145)|CODE_UNIT_FINISHED|BatchGDPRAnonymizeContacts
12:50:12.990 (4718160419)|CODE_UNIT_FINISHED|BatchGDPRAnonymizeContacts
12:50:12.990 (4719016441)|CODE_UNIT_STARTED|[EXTERNAL]|01pq0000000ajd6|BatchGDPRAnonymizeContacts
12:50:12.990 (4726103588)|SOQL_EXECUTE_BEGIN|[44]|Aggregations:0|SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email FROM AsyncApexJob WHERE Id = :tmpVar1
12:50:12.990 (4733869475)|SOQL_EXECUTE_END|[44]|Rows:1
12:50:12.990 (4734225747)|USER_DEBUG|[48]|DEBUG|Apex BatchGDPRAnonymizeContacts Completed
12:50:12.990 (4734367728)|USER_DEBUG|[49]|DEBUG|The batch Apex job processed 1 batches with 0 failures.
12:50:12.990 (4741437910)|CODE_UNIT_FINISHED|BatchGDPRAnonymizeContacts
12:50:12.990 (4743061969)|SOQL_EXECUTE_BEGIN|[25]|Aggregations:0|SELECT Id, FirstName, LastName, Email, Phone FROM Contact
12:50:12.990 (4747198855)|SOQL_EXECUTE_END|[25]|Rows:5
12:50:12.990 (4747514612)|USER_DEBUG|[26]|DEBUG|cListAnon: (Contact:{Id=003q000000w1HK0AAM, FirstName=test, LastName=Contact0, Email=test0@test.com, Phone=+12085550000}, Contact:{Id=003q000000w1HK1AAM, FirstName=test, LastName=Contact1, Email=test1@test.com, Phone=+12085550001}, Contact:{Id=003q000000w1HK2AAM, FirstName=test, LastName=Contact2, Email=test2@test.com, Phone=+12085550002}, Contact:{Id=003q000000w1HK3AAM, FirstName=test, LastName=Contact3, Email=test3@test.com, Phone=+12085550003}, Contact:{Id=003q000000w1HK4AAM, FirstName=test, LastName=Contact4, Email=test4@test.com, Phone=+12085550004})
12:50:12.990 (4747700346)|SOQL_EXECUTE_BEGIN|[29]|Aggregations:0|SELECT COUNT() FROM Contact WHERE FirstName='ANONYMOUS'
12:50:12.990 (4752840759)|SOQL_EXECUTE_END|[29]|Rows:0
12:50:12.990 (4752943948)|EXCEPTION_THROWN|[29]|System.AssertException: Assertion Failed: Expected: 5, Actual: 0
12:50:12.990 (4753035742)|FATAL_ERROR|System.AssertException: Assertion Failed: Expected: 5, Actual: 0

Class.BatchGDPRAnonymizeContacts_Test.testbatch: line 30, column 1
12:50:12.990 (4753045670)|FATAL_ERROR|System.AssertException: Assertion Failed: Expected: 5, Actual: 0

Based on the above, it seems that the Batch ran successfully and the QuickAction executed successfully on the batch of 5 records, but the re-query afterwards (just before the AssertEquals statement) shows the original data before the update.  

Any ideas what I might be missing here?
Amit Chaudhary 8Amit Chaudhary 8

Update your code like below
@isTest
private class BatchGDPRAnonymizeContacts_Test {
    
    @isTest static void testbatch() {
        // create 200 test contacts - this simulates one execute.
        // Important - the Salesforce.com test framework only allows you to
        // test one execute
        List <Contact> cList = new List<Contact>();
        Integer numContacts = 5;
            for(integer i = 0; i<numContacts; i++){
                Contact c = new Contact (FirstName='test', LastName='Contact'+i, Email='test'+i+'@test.com', Phone='+1208555000'+i);
                cList.add(c);
            }
        
        insert cList;
        
        Test.StartTest();
        String query = 'SELECT ID, FirstName, LastName, Email, Phone ' +
                    'FROM Contact ' +
                    ' LIMIT ' + numContacts;
        BatchGDPRAnonymizeContacts batch = new BatchGDPRAnonymizeContacts(query);
        
        ID batchprocessid = Database.executeBatch(batch, 50);
        Test.StopTest();
        List<Contact> cListAnon = [Select Id, FirstName, LastName, Email, Phone from Contact];
        system.debug('cListAnon: ' + cListAnon);
        
        System.AssertEquals( numContacts, database.countquery('SELECT COUNT() FROM Contact'));
        
    }
}

Remove WHERE FirstName='ANONYMOUS' from query/.
 
Antone KomAntone Kom
Amit,

Removing FirstName='ANONYMOUS' would allow the test class to pass but this assertion fails because the QuickAction has not really updated the records, which is what I want to test.  I am not trying to just get the test class to pass for the sake of passing without testing the actual use case.