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
tdevmantdevman 

batch insert > 200 problem

there is before trigger that passes records to tlist in the method.  I tested all behaviors per sfdc best practices. 1 positive, 1 negative, batch insert(200 records). However when i insert 201 records. I get System.ListException: List index out of bounds: 200.  How come i get this on the 201st record? other then that, everything works fine....

 

Best Answer chosen by Admin (Salesforce Developers) 
crop1645crop1645

tdevman --

 

so the problem is testPolicies.get(i).Id -- this method must not reference Policy__c objects that have 201 instances -- hence the list out of bounds.  You didn't post this method but look at it more closely

 

 

All Answers

Hengky IlawanHengky Ilawan

Could you post your test class?

 

-Hengky-

tdevmantdevman

the test class is actually huge since it tests many of our classes but here is the part that tests this class that produced the out of bounds

 

 

 

crop1645crop1645

Hmm -- Inserting 201 records should cause your before trigger to be invoked by SFDC twice - the first time with 200 records, the second time with 1 record

 

What line is the list index out of bounds reported on?

tdevmantdevman

For those of you reading this thread.  crop / Eric is really wise so this is a good thread to review

 

the stack track shows Class.Tests.testBatch: line 111, column 1

 

Line 111 is this one

Trans__c testT = testFactory.buildTestTrans(i, testPol.get(i).Id);

 

Trans__c.Pol__c = Pol.Id

 

 

crop1645crop1645

tdevman --

 

so the problem is testPolicies.get(i).Id -- this method must not reference Policy__c objects that have 201 instances -- hence the list out of bounds.  You didn't post this method but look at it more closely

 

 

This was selected as the best answer
Hengky IlawanHengky Ilawan

I think the size of testPolicies list could be less than 201, that's why you got the out of bound error.

How do you populate this testPolicies list?

 

-Hengky-

tdevmantdevman

crop - thanks again, i fixed it.

test1.buildTestT(i, testPget(i).Id);

 

So testPolicies is returning a list of Ids inserted in the previous for loop. When I looked at this again the 201st record of test policies wasn't inserted so i didn't return an id for testPolicies.get(i).Id) which causes in outofbounds since it;s a null value returned.

 

so....guess what? there is another method to  insert a batch of contacts int testContacts so when i changed all 3 loops to 201 then it worked!

 

you;re probably wondering  now why i have 3 seperate loops on these objects. I have similar before insert/update triggers on all 3 objects so i placed them all in the utilityTests class.  

 

Questions:

1. Is there a bettter way to structure the code? 

2. For triggers i create later on different objects, should i seperate the methods in a different class? otherwise my utilityclass wil just grow and grow

3. from code coverage point of view, i think there is no reason for me tests more than 200 records right?

4. can you load more than 200 in 1 batch in sfdc? this isn't  batch apex class but should i iterate through 10000 in each loop? I say 10000 since that is the total # of records to be processed in a single dml

5. What is the best way to test negative behavior for transactiontulities?

 

testUtil

@isTest private static void testBatch()
{

// batch insert test for trigger 

// batch insert test for triggerf

crop1645crop1645

tdevman:

 

I want to commend you for caring about this.  You clearly see that you will be maintaining a system over time and you want it to be elegant and bulletproof.  It is nice to see something other than the wham-bam-thank you-myTriggerIsDone approach that is often seen.

 

 

Q1. Is there a bettter way to structure the code? 

A1. You could have a separate method in your utilitiesTest class that the caller sets with the batchsize; then each of the for loops refers to the class variable set by the method rather than hard-coding to 201

 

 

Q2. For triggers i create later on different objects, should i seperate the methods in a different class? otherwise my utilityclass wil just grow and grow

A2. I personally like to have all my used-over-and-over-again test setup methods in a single class - especially if there is a set of default data I need to have (such as Oppo name, amount, closedate, stage) and where the caller (testMethod) can override some/all of the default data

 

Q3. from code coverage point of view, i think there is no reason for me tests more than 200 records right?

A3: Actually, testing 201 records doesn't have any more impact on code coverage than testing 2 records. The SFDC examples in the APEX doc only test with 200.  More interesting things to worry about in testmethods are:

 

  • Testing exception handling
  • Testing governor limits
  • Testing runAs different user profiles
  • Verifying through asserts that the database is updated correctly

 

Q4. can you load more than 200 in 1 batch in sfdc? this isn't  batch apex class but should i iterate through 10000 in each loop? I say 10000 since that is the total # of records to be processed in a single dml

A4: From the doc: "For Apex saved using Salesforce.com API version 20.0 or earlier, if an API call causes a trigger to fire, the batch of 200 records to process is further split into batches of 100 records. For Apex saved using Salesforce.com API version 21.0 and later, no further splits of API batches occur. Note that static variable values are reset between batches, but governor limits are not. Do not use static variables to track state information between batches."  

 

This implies that batches are of max size 200

 

See also: http://wiki.developerforce.com/page/Apex_Code_Best_Practices

 

 

 

Q5. What is the best way to test negative behavior for transactiontulities?

A5: This is a broad subject

 

  • If you want to test your catch blocks; then you have to force an exception to occur.  This sometimes is easy (inserting/updating a record that fails a known validation rule or required field rule). Sometimes this is hard like testing unexpected dml or queryexceptions -- I use static variables in a class. The Boolean variables are named 'force_npe_in_methodXXX'. I have testmethods that set this to true and the runtime code (within the try block) always includes either a method or statement that ultimately winds up as if (myClass.force_npe_in_methodXXX) {String s; s.toLowerCase();}  This will blow up the execution and cause the catch block to be invoked.  There are variants on this approach such as using interfaces where the testmethod  sets up for execution either the should-always-work interface or the guaranteed-to-cause-exceptioniinterface and the code being tested always uses whatever interface is established