+ Start a Discussion
MIKE_DAYMIKE_DAY 

Apex Trigger Code Coverage great but cannot get past the 'List Index Out of Bounds Issue'

Hi All,

This is driving me round the bend and I think i need a new perspective on it if at all possible?

My trigger has been designed to catpure very high level product information from a custom object and create an opportuntiy invoice with an associated price book and line items.

The trigger works every time on the sandbox and I really have put it through its paces hower I simply cannot get my Test Class to run

Trigger Code:

trigger insertNewOpportunity on Items_Used__c (before insert) {
// Create Variables
List<Opportunity> listOppor = new List<Opportunity>();
List<OpportunityLineItem> oliList = new List<OpportunityLineItem>();
Set<Id> SetAccId = new Set<Id>();
 
// Create Opportunity If required
if(trigger.New[0].RelatedTo__c != null) {
  Opportunity[] exOppo = [SELECT Id from Opportunity where Customer_Ref__c = :Trigger.New[0].RelatedTo__c]; // Find an Opportunity with the same Customer Reference as the product being inserted
  
    if(exOppo.IsEmpty()){ // If no Opportunity exisits for this record
      for(Items_used__c item : Trigger.new){      
        if(item.Account__c != null){ 
          Opportunity OppNew = new Opportunity(Customer_Ref__c = item.RelatedTo__c,AccountId = item.Account__c,StageName = 'Closed Won',CloseDate = System.today(),Type = 'Existing Business',Name = 'Invoice for Visit' +' '+ item.RelatedTo__c, RecordTypeID = '01220000000UWCK',Division__c = item.Division__c,Amount = 0.00,Quote_Due_By__c = System.today(),Referred_By__c = item.ReferredBy__c,LeadSource = 'Technician Sale');
         listOppor.add(OppNew);          
        }
       insert listOppor;  // Create Opportunity 
      }
    }
}
// Insert Opportunity Line Items
 for(Items_used__c lineitem : Trigger.new){ // For all the items being inserted
  List<PriceBook2> pbook = new List<PriceBook2>();
  if((lineitem.Account__c != null) && (lineitem.RelatedTo__c != null)){
  SetAccId.add(lineitem.Account__c);
   Map<Id, Account> MapAccount = new Map<Id, Account>([select Division__c, Price_Band__c from Account where Id IN :SetAccId]);
   if(MapAccount.get(lineitem.Account__c).Price_Band__c != null){ // If the Price Band picklist for the Account is not Empty
    pbook = [Select Id from PriceBook2 where Name = :MapAccount.get(lineitem.Account__c).Price_Band__c]; 
   } // Else if the Division picklist for the Account is one of the following:
   else if(lineitem.Division__c == 'Pest'){ pbook = [Select Id from PriceBook2 where Id = '01s20000000PuSW'];} // Select the Pest Division Standard Price Book
   else if(lineitem.Division__c == 'Fire') { pbook = [Select Id from PriceBook2 where Id = '01s20000000Pz7tAAC'];} // Select the Fire Division Standard Price Book
   else if(lineitem.Division__c == 'Water') { pbook = [Select Id from PriceBook2 where Id = '01s20000000PvJCAA0'];} // Select the Pest Division Standard Price Book
   List<PriceBookEntry> pbe = new List<PriceBookEntry>(); // Get the Price Book Id
   pbe = [select Id, Pricebook2Id, UnitPrice from PriceBookEntry where Name = :lineitem.Item_Used__c AND PriceBook2Id = :pbook[0].Id];
   List<Opportunity> Opp = New List<Opportunity>(); // Get the related Opportunity Record
   Opp = [Select Id from Opportunity where Customer_ref__c = :lineitem.RelatedTo__c];
   Double q = Double.valueOf( lineitem.Quantity__c ); // Change the QTY Picklist to a numeric
   // Add all the Line item information to the List
   OpportunityLineItem oli = new OpportunityLineItem (OpportunityId = Opp[0].Id,PricebookEntryId = pbe[0].Id,Quantity = q, UnitPrice = pbe[0].UnitPrice);
   oliList.add(oli);
   insert oliList; // Insert the Line Item
   }  
 } 
}

Test Code:

@istest
private class testItemsUsed{
static testMethod void testItemsUsed1(){
 Account a1 = new Account(Name = 'Test Account', Division__c = 'Fire', Price_Band__c ='Fire Division Band C', Phone = '029208622998', RecordTypeId = '01220000000UVOw', Status__c='Active', Type = 'Customer');
 insert a1;
 Items_used__c i1 = new Items_Used__c(Quantity__c = '1', RelatedTo__c = 'A', Division__c = 'Fire', Account__c = a1.Id, ReferredBy__c='TEST USER', Item_Used__c = '1 Kg Powder Extinguisher');
 insert i1;
}
static testMethod void testItemsUsed2(){
 Account a2 = new Account(Name = 'Test Account', Division__c = 'Water', Phone = '029208622998', RecordTypeId = '01220000000UVOw', Status__c='Active', Type = 'Customer');
 insert a2;
 Items_used__c i2 = new Items_Used__c(Quantity__c = '1', RelatedTo__c = 'B', Account__c = a2.Id, Division__c = 'Water', ReferredBy__c='TEST USER', Item_Used__c = 'MISC');
 insert i2;
 Items_used__c i3 = new Items_Used__c(Quantity__c = '2', RelatedTo__c = 'B', Account__c = a2.Id, Division__c = 'Water', ReferredBy__c='TEST USER', Item_Used__c = 'MISC');
 insert i3;
}

}

Failure Warning:

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, insertNewOpportunity: execution of BeforeInsert caused by: System.ListException: List index out of bounds: 0 Trigger.insertNewOpportunity: line 34, column 1: []

I have run the query that pulls through the records that should populate in line 34 throught eh developer console (Select Id from PriceBook2 where Id = '01s20000000PuSW' and also Select Id from PriceBook2 where Name = 'Fire Division Band A') and it brings back records.

I have tested and tested but cannot get this List index out of bounds issue to resolve itself

PLEASE HELP!!!!!

Thanks

Mike
Best Answer chosen by Admin (Salesforce Developers) 
MIKE_DAYMIKE_DAY

I dont know if this is the correct way of working through this but i simply added "IsTest(SeeAllData=true)" to the start of the test class and it deplyaed with 100% test coverage

 

Perhaps not ideal but a workaround for the exposure to the price book entry issues none the less

 

Many thanks for all your help and pointing me in the right direction

 

Mike

All Answers

turbo2ohturbo2oh

You don't create a price book entry record in your test coverage.

MIKE_DAYMIKE_DAY

hi turbo2oIh, 

 

Thanks for this, is there a workaround or is this a show stopper as the functionality works great over on the Sandbox and I would love to get this over to the live system.

 

I have seen similar triggers for Opportunity Line creation but not their test coverage

 

Thanks

 

Mike

 

turbo2ohturbo2oh

It looks like your test coverage is relying on records being available in the database, which isn't a good practice. Are there pricebook entry records in the live system? Is it failing when you're trying to deploy it?

MIKE_DAYMIKE_DAY

 

I did notice that the record Id for a Price Book on the Sandbox is exactly the same as in Production so I hard coded them in after getting failing to deploy.  

 

The test failure is both on the Sandbox and Production but the code coverage is 81% on both?

turbo2ohturbo2oh

The issue I believe is that even though you can query and find records manually, when it does the query while executing the test coverage it is unable to find the price book entry records. The scope of the test coverage should be contained to only records that have been created inside it. I believe in older API versions it could still grab live data, but it may have been changed in a recently API version. Try creating some price book entry records inside your test coverage, and see if that gets rid of the list out of bounds error.

MIKE_DAYMIKE_DAY

Thanks for all your help on this but, after trying to add price book entry records to my test I get the same issue.  I cant fin any documentation on this limitation so could you point me in the right direction please?

 

@istest
private class testItemsUsed{

 static testMethod void testItemsUsed1(){
 Product2 p1 = new Product2(Name='Testing Product', IsActive = TRUE);
 insert p1;
        
 String standardPriceBookId = '01s20000000EzZH';
 PricebookEntry pbe1 = new PricebookEntry(Pricebook2Id=standardPriceBookId,UnitPrice = 1.00, IsActive = TRUE, Product2Id=p1.Id);
 insert pbe1;

 String PestPriceBookId = '01s20000000PuSW';
 PricebookEntry pbe2 = new PricebookEntry(Pricebook2Id=PestPriceBookId,UnitPrice = 1.00,IsActive = TRUE, Product2Id=p1.Id);
 insert pbe2;

 String FirePriceBookId = '01s20000000Pz7tAAC';
 PricebookEntry pbe3 = new PricebookEntry(Pricebook2Id=FirePriceBookId,UnitPrice = 1.00,IsActive = TRUE, Product2Id=p1.Id);
 insert pbe3;

 String WaterPriceBookId = '01s20000000PvJCAA0';
 PricebookEntry pbe4 = new PricebookEntry(Pricebook2Id=WaterPriceBookId,UnitPrice = 1.00,IsActive = TRUE, Product2Id=p1.Id);
 insert pbe4;

 Account a1 = new Account(Name = 'Test Account', Division__c = 'Fire', Price_Band__c ='Fire Division Band C', Phone = '029208622998', RecordTypeId = '01220000000UVOw', Status__c='Active', Type = 'Customer');
 insert a1;
 Items_used__c i1 = new Items_Used__c(Quantity__c = '1', RelatedTo__c = 'A', Division__c = 'Fire', Account__c = a1.Id, ReferredBy__c='Ken Dodd', Item_Used__c = 'Testing Product');
 insert i1;
}

 static testMethod void testItemsUsed2(){
 Product2 p2 = new Product2(Name='Testing Product 2', IsActive = TRUE);
 insert p2;
        
 String standardPriceBookId = '01s20000000EzZH';
 PricebookEntry pbe5 = new PricebookEntry(Pricebook2Id=standardPriceBookId,UnitPrice = 1.00, IsActive = TRUE, Product2Id=p2.Id);
 insert pbe5;

 String PestPriceBookId = '01s20000000PuSW';
 PricebookEntry pbe6 = new PricebookEntry(Pricebook2Id=PestPriceBookId,UnitPrice = 1.00,IsActive = TRUE, Product2Id=p2.Id);
 insert pbe6;

 String FirePriceBookId = '01s20000000Pz7tAAC';
 PricebookEntry pbe7 = new PricebookEntry(Pricebook2Id=FirePriceBookId,UnitPrice = 1.00,IsActive = TRUE, Product2Id=p2.Id);
 insert pbe7;

 String WaterPriceBookId = '01s20000000PvJCAA0';
 PricebookEntry pbe8 = new PricebookEntry(Pricebook2Id=WaterPriceBookId,UnitPrice = 1.00,IsActive = TRUE, Product2Id=p2.Id);
 insert pbe8;

 Account a2 = new Account(Name = 'Test Account', Division__c = 'Water', Phone = '029208622998', RecordTypeId = '01220000000UVOw', Status__c='Active', Type = 'Customer');
 insert a2;
 Items_used__c i2 = new Items_Used__c(Quantity__c = '1', RelatedTo__c = 'B', Account__c = a2.Id, Division__c = 'Water', ReferredBy__c='Ken Dodd', Item_Used__c = 'Testing Product 2');
 insert i2;
 Items_used__c i3 = new Items_Used__c(Quantity__c = '2', RelatedTo__c = 'B', Account__c = a2.Id, Division__c = 'Water', ReferredBy__c='Ken Dodd', Item_Used__c = 'Testing Product 2');
 insert i3;
}

}

 

 

 

 

 

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, insertNewOpportunity: execution of BeforeInsert caused by: System.ListException: List index out of bounds: 0 Trigger.insertNewOpportunity: line 34, column 1: []

MIKE_DAYMIKE_DAY

I dont know if this is the correct way of working through this but i simply added "IsTest(SeeAllData=true)" to the start of the test class and it deplyaed with 100% test coverage

 

Perhaps not ideal but a workaround for the exposure to the price book entry issues none the less

 

Many thanks for all your help and pointing me in the right direction

 

Mike

This was selected as the best answer
turbo2ohturbo2oh

Yeah based on that error it still sounds like you were missing some records in your testmethod that existed in the database. What you did is basically allow access to the real data for the testmethod. You may have also been able to do this by rolling back the API version in the metadata, I'm not positive though. If it worked that's good news, though probably not a best practice.