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
klaus maierklaus maier 

Discussion Testclass : bulkify code

Hello guys,
as best practice i want to bulkyify my triggers and class methodes as good as poosible. How many records do i have to create/test to call a bulk test ? If i create a lot of test data in my @testsetup method i am running into the cpu limit.

For example. A method queries the Opportunity.AccountId of some specific opportunitylineitems and put them in a set of ids. To test this method, i have to create x Accounts with x  (min 1) opportunities and x (min 1) opportunitylineitems. 

So my questions:
- how many records do you use in your testclasses ? per object and overall
- is it best practice to use Test.startTest() and Test.stopTest() in the testsetup method ?

 
Best Answer chosen by klaus maier
Andrew GAndrew G
Hi Klaus

To some degree, it depends on what your trigger or class is doing.  

If we are talking about DMLs (inserts/updates), then the limit of batch size is 200.   So lets say that the code intent is that when an Account is inserted, create a default contact for each account.  IN this case, i would create 201 accounts to insert as that would ensure you can make it past the batch size of 200.

ref: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers.htm 
Note that earlier API versions were limited to 100

If we are talking about testing SOQL results, depending on the literature you read, its either 200/500/2000.
ref: https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_changing_batch_size.htm

For myself, i do 201 records, as it achieves the DML requirement and the minimum SOQL requirement.  Also in the above link , note about when querying custom fields in object (limited to 200).

As for use of the Test.start and Test.stop.  Don't use them in the Test Setup method.  What they do is reset the Limits for the Test run.

So your Test setup should simply insert test data, and then in you Test Method, when you are invoking the code that you want to test, Test.Start() just before you invoke that call so that the DML limits are reset to zero so that you are testing that code will run in a live situation. 

For example, you have a lot to do in your test setup and you write 20 records to setup your test data.  If you did not use Test.start() , when you invoke the code, you will already have 20 DMLs, so your test would not directly mimic the real situation where the code is invoked from scratch.

Note also, that you should then use the Test.stop() before you query your test data to perform assets, because, among other things, ensures that all the DMLs in the test method are completed before you query your test data and therefore can be assured that the assertions will run correctly.

A basic structure for the use of test.start/test.stop would be as below.
@IsTest
private class someTest(){
  
  @TestSetup
  static void dataSetup(){
    //insert a heap of test data
  }

  @IsTest
  static void someTestMethod(){
    //get some of the test data that was inserted
    Test.startTest();
    //invoke the method we are testing using the test data
    Test.stopTest();
    //do a query to get the updated test data and then do some asserts
  }
  @IsTest static void someTestMethod2(){
    //get some of the test data that was inserted 
    Test.startTest(); 
    //invoke the method we are testing using the test data 
    Test.stopTest(); 
    //do a query to get the updated test data and then do some asserts 
  }
}


HTH
Andrew

All Answers

ANUTEJANUTEJ (Salesforce Developers) 
Hi Klaus,

As stated in https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm#:~:text=The%20maximum%20number%20of%20rows,that%20insert%2010%2C000%20rows%20each. "MAX_DML_ROWS limit in Apex testing
The maximum number of rows that can be inserted, updated, or deleted, in a single, synchronous Apex test execution context, is limited to 450,000. For example, an Apex class can have 45 methods that insert 10,000 rows each. If the limit is reached, you see this error: Your runallTests is consuming too many DB resources." generally you can follow the rules stated in below link for bulkifying the trigger.

>> https://developer.salesforce.com/page/Best_Practice%3A_Bulkify_Your_Code#:~:text=The%20term%20bulkifying%20Apex%20code,records%20in%20that%20given%20batch.

I hope this helps and in case if this comes handy can you please choose this as best answer so that it can be used by others in the future.

Regards,
Anutej
klaus maierklaus maier
@ANUTEJ
thanks, could you give me a advice for my two questions ?

- how many records do you use in your testclasses ? per object and overall
- is it best practice to use Test.startTest() and Test.stopTest() in the testsetup method ?
ANUTEJANUTEJ (Salesforce Developers) 
So as per the logic you have written in the method you can have the number of records that are necessary as per your implementation, i.e., for example, if there is an object and there is a condition you are testing in the trigger if the email field is empty then there are two scenarios one where the email field is not empty and second when the email field is empty in the inserting records, so in the test class, you would be testing these two scenarios by inserting two records one satisfying the condition and another that doesn't evaluate to true.
If the trigger runs perfectly for one record then it would run the same for the different number of records that have similar data.

As stated in https://salesforce.stackexchange.com/questions/80949/when-to-use-test-starttest which mentions the use of both the methods: "Test.startTest() and Test.stopTest() exist primarily to allow you to reset the governor limits within the context of your test execution and to be able to test asynchronous methods. These two statements cannot be called more than once within a testMethod."
You could have a look at the above link for the explanation with an example description.

Does this address the question?
Andrew GAndrew G
Hi Klaus

To some degree, it depends on what your trigger or class is doing.  

If we are talking about DMLs (inserts/updates), then the limit of batch size is 200.   So lets say that the code intent is that when an Account is inserted, create a default contact for each account.  IN this case, i would create 201 accounts to insert as that would ensure you can make it past the batch size of 200.

ref: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers.htm 
Note that earlier API versions were limited to 100

If we are talking about testing SOQL results, depending on the literature you read, its either 200/500/2000.
ref: https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_changing_batch_size.htm

For myself, i do 201 records, as it achieves the DML requirement and the minimum SOQL requirement.  Also in the above link , note about when querying custom fields in object (limited to 200).

As for use of the Test.start and Test.stop.  Don't use them in the Test Setup method.  What they do is reset the Limits for the Test run.

So your Test setup should simply insert test data, and then in you Test Method, when you are invoking the code that you want to test, Test.Start() just before you invoke that call so that the DML limits are reset to zero so that you are testing that code will run in a live situation. 

For example, you have a lot to do in your test setup and you write 20 records to setup your test data.  If you did not use Test.start() , when you invoke the code, you will already have 20 DMLs, so your test would not directly mimic the real situation where the code is invoked from scratch.

Note also, that you should then use the Test.stop() before you query your test data to perform assets, because, among other things, ensures that all the DMLs in the test method are completed before you query your test data and therefore can be assured that the assertions will run correctly.

A basic structure for the use of test.start/test.stop would be as below.
@IsTest
private class someTest(){
  
  @TestSetup
  static void dataSetup(){
    //insert a heap of test data
  }

  @IsTest
  static void someTestMethod(){
    //get some of the test data that was inserted
    Test.startTest();
    //invoke the method we are testing using the test data
    Test.stopTest();
    //do a query to get the updated test data and then do some asserts
  }
  @IsTest static void someTestMethod2(){
    //get some of the test data that was inserted 
    Test.startTest(); 
    //invoke the method we are testing using the test data 
    Test.stopTest(); 
    //do a query to get the updated test data and then do some asserts 
  }
}


HTH
Andrew
This was selected as the best answer