[SalesForce] Test Class Data Setup – Governor Limits

The test method gets its set of governor limits, exclusive of the content between startTest and stopTest. I have faced the issue of 101 SOQL Governor Limits in test classes and mostly I have been able to resolve it by either using startTest/stopTest or by splitting into a new methods. We will have to set up test data in the beginning of the test method and then do the actual testing(logic, governor limits bulk testing, performance evaluation etc). But what will happen if we reach a situation where we hit the governor limits in a test method at the time of data setup itself.

Suppose I want to test some functionality of adding attachments to child products of opportunity. My business logic dictate that I do the following to create an opportunity product:

Data Model : Account > Contact > Opportunity > OpportunityProduct

  1. Create an account
  2. Create a contact under that account
  3. Create an opportunity under the contact
  4. Create a product under the opportunity
  5. Create an attachment under that product

Consider that the org is extensive and many custom functionalities exists for all these objects. So if there are 30 SOQL queries in the triggers for each of these objects – the test class will fail due to 101 SOQL even before reaching step 5.

I agree the situation I presented is pretty exaggerated – 30 queries for each object is pretty bad. But I hope I am making the picture clear, that in big projects, isn't there a possibility where we run into governor limits in test class just at the time of data creation.I am actually running into this already.

Please do share your thoughts.

Best Answer

You may have to limit the number of records you create, even down to one per type. If it's still hitting the limit at that point, you're pretty much SOL. As a last resort, you can use SeeAllData=true so that you aren't hitting triggers. Test.loadData won't really help as it still fires triggers.

One solution you can implement as you build out your org (which may be more difficult to implement with existing functionality) is to build trigger stop flags into your handler pattern. My template looks something like:

public with sharing class LeadTriggerHandler
{
    @TestVisible static Boolean bypassTrigger = false;

    final List<Lead> newRecords;
    final Map<Id, Lead> oldMap;
    public LeadTriggerHandler(List<Lead> newRecords, Map<Id, Lead> oldMap)
    {
        this.newRecords = newRecords;
        this.oldMap = oldMap;
    }

    public void beforeInsert()
    {
        if (bypassTrigger) return;
        //LeadSerivices.method1(newRecords);
    }
    public void afterInsert()
    {
        if (bypassTrigger) return;
        //LeadSerivices.method2(newRecords);
    }

    public void beforeUpdate()
    {
        if (bypassTrigger) return;
        //LeadSerivices.method1(newRecords);
    }
    public void afterUpdate()
    {
        if (bypassTrigger) return;
        //LeadSerivices.method3(newRecords);
    }
}

Then in your test you can just do:

LeadTriggerHandler.bypassTrigger = true;
insert new Lead(/*data*/);
LeadTriggerHandler.bypassTrigger = false;

This flagging strategy can dramatically streamline your tests, and can be implemented in a variety of ways. The key is that the flag is static, though I think it is important to keep it private if at all possible.

Related Topic