[SalesForce] RecursiveCheck prevents trigger from running during tests

I am writing a test class to a handler class called from a trigger. And due to recursive trigger I had to implement CheckRecursive in the trigger and this works fine, until I start testing. Then the trigger only runs once even after I use Test.startTest() and Test.stopTest.

This is my trigger

if(trigger.isInsert){
    if(checkRecursive.contactAfterInsertTriggerRunOnce()){
        ContactHandler.callAmethod(trigger.newMap.keyset());
    }
} if(trigger.isUpdate){
if(checkRecursive.contactAfterUpdateTriggerRunOnce()){
    ContactHandler.createContactListToSendToForUpdate(trigger.new, trigger.oldMap);       
    ContactHandler.contactMergeLearners(trigger.new);
    }
} if(trigger.isDelete){
    if(checkRecursive.contactAfterDeleteTriggerRunOnce()){
        ContactHandler.deleteUsersList(trigger.old);
    }
}

This is the checkRecursive class

public Class checkRecursive{
contactAfterInsertTriggerRun
public static boolean contactAfterInsertTriggerRunOnce(){
    if(contactAfterInsertTriggerRun){
        contactAfterInsertTriggerRun=false;
        return true;
    } else {
    return contactAfterInsertTriggerRun;
    }
}

And this is my test class

@isTest
private class ContactHandlerTest {

    @testSetup static void setupTestData(){


        list<Account> accList = new list<Account>();

        Account stdAcc = TestFactory.getAccount('Standard testAcc');
        accList.add(stdAcc);

        Account reselAcc = TestFactory.getAccount('Reseller testAcc');
        reselAcc.Reseller__c = 'Partner';
        accList.add(reselAcc);

        Account distributorAcc = TestFactory.getAccount('Distributor testAcc');
        distributorAcc.Distributor__c = 'Partner';
        accList.add(distributorAcc);

        insert accList;

    }

    static testMethod void testCreateContacts() {
        // Get account from test
        Account acc = [SELECT Id, Reseller__c, Distributor__c FROM Account WHERE Reseller__c = '' AND Distributor__c = '' LIMIT 1];

        // Create an list for contacts
        list<Contact> contactListBeforeDelete = new list<Contact>(); 
        contactListBeforeDelete = [SELECT Id FROM Contact];
        system.assertEquals(0, contactListBeforeDelete.size(), 'There are ' + contactListBeforeDelete.size() + ' contacts there should be 0 before delete');

        Test.startTest();
        Contact stdContact = testFactory.getContact(acc, 'Standard');
        insert stdContact;
        Test.stopTest();

        list<Contact> contactListAfterDelete = new list<Contact>(); 
        contactListAfterDelete = [SELECT Id FROM Contact];
        system.assertEquals(1, contactListAfterDelete.size(), 'There are ' + contactListAfterDelete.size() + ' contacts there should be 1 after delete');
    }

My problem is that the trigger is never run more than once. When I update the the contact the trigger does not run again and I do not understand why. Can any of you spot an error?
Or is it just very difficult to test a trigger with a recursive check in it. I thourght about inserting the contact in the @testSetup and then just updating it. But I just don't understand why that should be nessary.

Best Answer

First of all, using a simple Boolean variable for recursion control is a flawed approach if you ever will update in a transaction more than 200 records (like in some controller/REST service/execute anonymous/platform event trigger). A better solution involves managing a set of IDs and checking to see if the ID has been 'visited' before to see if you should ignore it during the 2nd, 3rd, ... trigger execution. You can read more about this here and sfdcfox's answer in the SFDC Forum here.

As to the testmethod issue -- after you do DML on a trigger-recursion-controlled sobject, you need to clear the recursion "flags" as if a new user transaction were occuring. That is, in your case, the static variable have to go back to their initialized state.

Add to your recursion control class some sort of reset() method to clear the "flags"

Related Topic