I'm wondering if there is a way to get multiple transactions (with different contexts as far as static variables are concerned) within one test.
I have a Trigger handler class where there is some caching of a query to get data from a related object. This is done with a static member Map holding the data through the transaction. This all works well with Users interacting with the system, but it falls over when I'm trying to write an integration test to test edits, as there is no new transaction so the static Map remains cached with the old data.
As a simplified version of my actual code, there are two custom objects, Employee and Personal, and a trigger on Personal that updates Personal.Email__c to have the same value as Employee.Email__c (I can't just use a formula field because those can't be used in alerts).
public class PersonalTriggerHandler { private static Map<Id, Employee__c> employeeDetails; private void updateEmails(List<Personal__c> personals) { Set<Id> employeeIds = new Set<Id>(); for (Personal__c personal : personals) { employeeIds.add(personal.Employee__c); } if (employeeDetails == null) { employeeDetails = [SELECT Email__c FROM Employee__c WHERE Id IN :employeeIds]; } for (Personal__c personal : personals) { personal.Email = employeeDetails.get(personal.Employee__c).Email__c; } } public void onBeforeInsert(List<Personal__c> personals) { updateEmails(personals); } public void onBeforeUpdate(List<Personal__c> personals) { updateEmails(personals); } } @IsTest private class PersonalIntegrationTest { @IsTest static void whenPersonalUpdated_thenEmailIsSet { Employee__c employee = new Employee__c(Email__c='[email protected]'); insert employee; Personal__c personal = new Personal__c(Employee__c=employee.Id); insert personal; employee.Email__c = '[email protected]'; update employee; Test.startTest(); update personal; Test.stopTest(); Personal__c checkPersonal = [SELECT Email__c FROM Personal__c WHERE Id = :personal.Id]; System.assertEquals('[email protected]', checkPersonal.Email__c, 'Email should be updated from Employee'); } } (Note: if I've mis-typed anything here, let me know; I've basically reconstructed a much larger code-base to strip it down to basics. Also, the trigger is set up to call the appropriate methods, but I didn't think anyone would need to see that)
My assert fails - the personal record still has an email of [email protected] because when I first inserted the personal record it populated the static map and the update is then happening within the same transaction. I'm wondering if there is any way to create a separate transaction within one test method - I had hoped that Test.startTest() would do so, but apparently not.
Having seen discussions here Is a single APEX test case considered a transaction? and here Error: MIXED_DML_OPERATION on setup and non-setup objects I tried using System.runAs(), but that does not work. Seems it creates a separate enough context to get around mixed DML, but not an actually separate transaction :(