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
Dipak NikamDipak Nikam 

Test.StartTest showing me weird behaviour. Dont know what I am missing in below code.

@isTest
public class ValidateTestStartMethod {
 static testmethod void method1() {
     
    for (Integer i= 0;i<95;i++) {
         Account[]acctlist = [select id from Account limit 1];
     }
     
     Test.startTest();
     for (Integer i=0;i<=10;i++) {
         Account [] ac = [select id from Account limit 1];
     }
     Test.stopTest();
 }

I completely understand as per best practices we should not write any query inside the for loop. Here I just wanted test the purpose of Test.StartTest and Test.StopTest methods. 

As per Salesforce document, Test.StartTest allocates fresh set of governor limits. But unfortunately above code failing due to SOQL query limit exception. Any thoughts, why is it so ?  Thanks in advance :)

User-added image



Regards,
Dipak Nikam
 
Best Answer chosen by Dipak Nikam
bob_buzzardbob_buzzard
This is a known issue that is fixed in the Spring 16 release - from the release notes:

--- snip ---

Call Test.startTest() to Reliably Reset Limits in Apex Tests

A block of test code enclosed by the Test.startTest() and Test.stopTest() methods now reliably receives its own block of governor limits. Test.startTest() stores your per-transaction limit counters and temporarily resets them to zero. Test.stopTest() restores your limit counters to pre-Test.startTest() values. When your test method finishes, all per-transaction limits reset to zero. Previously, some limits, such as for SOQL queries, didn’t always reset inside a Test.startTest()/Test.stopTest() block.

--- snip ---

All Answers

bob_buzzardbob_buzzard
This is a known issue that is fixed in the Spring 16 release - from the release notes:

--- snip ---

Call Test.startTest() to Reliably Reset Limits in Apex Tests

A block of test code enclosed by the Test.startTest() and Test.stopTest() methods now reliably receives its own block of governor limits. Test.startTest() stores your per-transaction limit counters and temporarily resets them to zero. Test.stopTest() restores your limit counters to pre-Test.startTest() values. When your test method finishes, all per-transaction limits reset to zero. Previously, some limits, such as for SOQL queries, didn’t always reset inside a Test.startTest()/Test.stopTest() block.

--- snip ---
This was selected as the best answer
Ranjan SahaRanjan Saha
Hi Dipak,
The issue is with the way you have written the code inside Test limits reset context. The code that is posted by you hits the limit because the compiler doesn't qualify it as a reset context.That's why your query counts are 95 outside reset limit context and 6 inside reset limit context respectively. The Apex Compilet is a intelligent one, it will not switch the context unless there some actual code to be executed. I did that and the test class runs without any error. Here is the code.



@isTest
public class ValidateTestStartMethod {
 static testmethod void method1() {
     
    for (Integer i= 0;i<95;i++) {
         Account[]acctlist = [select id from Account limit 1];
     }
     
     Test.startTest();
     system.debug('test start'+Limits.getQueries());
     for (Integer i=0;i<=10;i++) {
         Account [] ac = [select id from Account limit 1];
     }
     
     Test.stopTest();
 }
 }
Dipak NikamDipak Nikam
Hi Bob,

Thank you for clarifying this :)  

One more observation I would like to share. I was working on the same code later on after posting this question on the forum and found some interesting stuff.
I just added System.Debug to find out number queries issued during test execution and it ran successfully. No more exception.

If I add debug just to print some static value, then code throws exception(i.e. SOQL limit exception).  
 
Any idea, why  ?      

@isTest
public class ValidateTestStartMethod {
 static testmethod void method1() {
     
    for (Integer i= 0;i<95;i++) {
         Account[]acctlist = [select id from Account limit 1];
     }
     system.debug('Query Count Before StartTest-------'+Limits.getQueries());
     Test.startTest();
     system.debug('Query Count After StartTest-------'+Limits.getQueries());
     for (Integer i=0;i<=10;i++) {
         system.debug('Queries inside Loop-------'+i+'------'+Limits.getQueries());
         Account [] ac = [select id from Account limit 1];
      }
     Test.stopTest();
 }



Regards,
Dipak Nikam 


 
bob_buzzardbob_buzzard
That is why the word 'reliably' is used - it will reset in all cases, rather than it being affected by what the compiler wants to optimise.