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
jd_labbejd_labbe 

Unit Testing assistance needed - only getting 72% code coverage

 Hello,

 

I'm about to pull my hair out here trying to unit test this trigger in order to move it to production. This passes all of my manual use case testing, but I only get 72% code coverage with the apex class unit testing. Not sure what's happening here. Any assistance would be appreciated.

 

Code is provided below, but the following lines are highlighted in red on the test debug:

 

createdsr.add(new Service_Request__c (Opportunity__c = o.Id, Account__c=o.AccountID, Name = o.Name, Service_Group__c = 'RFx'));

 

 

system.debug(Ex);

 

 

Apex Trigger Code:

 

trigger AutomateCreateDSR on Opportunity (after insert,after update) {
List<Service_Request__c> createdsr = new List <Service_Request__c> {};
List<Id> oppIds = new List<Id>{};

for (opportunity o : trigger.new) {
oppIds.add(o.id);

{
List<Service_Request__c> dsr= [SELECT Id,Opportunity__c,Account__c,Name,Service_Group__c FROM Service_Request__c WHERE Opportunity__c IN :oppIds];
if (dsr.size()==0 && o.Point_by_Point_Response__c ==True)
{
createdsr.add(new Service_Request__c (Opportunity__c = o.Id, Account__c=o.AccountID, Name = o.Name, Service_Group__c = 'RFx'));
}

try {
insert createdsr;
}
catch (Exception Ex)
{
system.debug(Ex);
}
}
}
}
 
 
 
 

 

Apex Class Test Code:

 

@isTest
private class TestAutomateDSR {

   private static Opportunity opportunity1;
    
    static {
        
        opportunity1 = new Opportunity();
        opportunity1.Name = 'TestOpp1';
        opportunity1.StageName = '1-Targeted';
        opportunity1.CloseDate = Date.valueOf('2011-09-01');
        opportunity1.Amount = 200;
        //opportunity1.Has_Orders__c = false;

        insert opportunity1;            
    }
        
    static testMethod void testhasDSRs() {
    List<Service_Request__c> createdsr = new List <Service_Request__c> {};
   
    createdsr.add(new Service_Request__c (Opportunity__c = opportunity1.Id, Account__c=opportunity1.AccountID, Name = opportunity1.Name, Service_Group__c = 'RFx'));  
            
      try {
  insert createdsr;
   }
  catch (Exception Ex)
  {
  system.debug(Ex);
   }
   }
   }
 

 

Best Answer chosen by Admin (Salesforce Developers) 
Shashikant SharmaShashikant Sharma

My mistake here just misunderstood your req, you want to create a record only when record does not exists.

 

This should work properly for you.

 

trigger AutomateCreateDSR on Opportunity (after insert,after update) {
List<Service_Request__c> createdsr = new List <Service_Request__c> {};
List<Id> oppIds = new List<Id>{};
for (opportunity o : trigger.new) {
oppIds.add(o.id);
}


MAP<ID , List<Service_Request__c>> mapSR = new Map<ID , List<Service_Request__c>>();

List<Service_Request__c> listtempSR =  new List<Service_Request__c>();
for(Service_Request__c dsrObj :  [SELECT Id,Opportunity__c,Account__c,Name,Service_Group__c FROM Service_Request__c WHERE Opportunity__c IN :oppIds])
{
   if(mapSR.containsKey(dsrObj.Opportunity__c))
    {  
       listtempSR = mapSR.get(dsrObj.Opportunity__c);
     }
   else
    {
       listtempSR =  new List<Service_Request__c>();
    }
   
   listtempSR.add(dsrObj);
   mapSR.put(dsrObj.Opportunity__c , listtempSR);
       

}

for (opportunity o : trigger.new) 
{
    if ((!mapSR.contaisKey(o.id)) && o.Point_by_Point_Response__c ==True)
    {
        createdsr.add(new Service_Request__c (Opportunity__c = o.Id, Account__c=o.AccountID, Name = o.Name, Service_Group__c = 'RFx'));
    }
    
}

    try {
    insert createdsr;
    }
    catch (Exception Ex)
    {
    system.debug(Ex);
    }
    

 

All Answers

Shashikant SharmaShashikant Sharma

Here is your test class

 

@isTest
private class TestAutomateDSR {

   private static Opportunity opportunity1;
    
    static {
        
        opportunity1 = new Opportunity();
        opportunity1.Name = 'TestOpp1';
        opportunity1.StageName = '1-Targeted';
        opportunity1.CloseDate = Date.valueOf('2011-09-01');
        opportunity1.Amount = 200;
        //opportunity1.Has_Orders__c = false;

        insert opportunity1;            
    }
        
    static testMethod void testhasDSRs() {
    List<Service_Request__c> createdsr = new List <Service_Request__c> {};
   
    createdsr.add(new Service_Request__c (Opportunity__c = opportunity1.Id, Account__c=opportunity1.AccountID, Name = opportunity1.Name, Service_Group__c = 'RFx'));  
            
   
  insert createdsr;
  update opportunity1;
  
  
   }
}

 It will increase your code coverage, but You need to update your trigger as well for bulk data handling. YOu are using SOQL and dml in for loop.

 

Your updated Trigger

 

trigger AutomateCreateDSR on Opportunity (after insert,after update) {
List<Service_Request__c> createdsr = new List <Service_Request__c> {};
List<Id> oppIds = new List<Id>{};
for (opportunity o : trigger.new) {
oppIds.add(o.id);
}


MAP<ID , List<Service_Request__c>> mapSR = new Map<ID , List<Service_Request__c>>();

List<Service_Request__c> listtempSR =  new List<Service_Request__c>();
for(Service_Request__c dsrObj :  [SELECT Id,Opportunity__c,Account__c,Name,Service_Group__c FROM Service_Request__c WHERE Opportunity__c IN :oppIds])
{
   if(mapSR.containsKey(dsrObj.Opportunity__c))
   listtempSR = mapSR.get(dsrObj.Opportunity__c)
   else
   listtempSR =  new List<Service_Request__c>();
   
   listtempSR.add(dsrObj);
   mapSR.put(dsrObj.Opportunity__c , listtempSR);
       

}

for (opportunity o : trigger.new) 
{
    List<Service_Request__c> dsr = mapSR.get(o.id)
    if (dsr.size()==0 && o.Point_by_Point_Response__c ==True)
    {
        createdsr.add(new Service_Request__c (Opportunity__c = o.Id, Account__c=o.AccountID, Name = o.Name, Service_Group__c = 'RFx'));
    }
}

    try {
    insert createdsr;
    }
    catch (Exception Ex)
    {
    system.debug(Ex);
    }
    

}

 

jd_labbejd_labbe

Thanks for the assistance!!

 

I first modified my trigger per your recommendation, but now receive the following error when creating a new opportunity record and attempting to save for the first time:

 

Apex trigger AutomateCreateDSR caused an unexpected exception, contact your administrator: AutomateCreateDSR: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.AutomateCreateDSR: line 28, column 9

Error: Invalid Data. 
Review all error messages below to correct your data.

 

 

Line 28 is as follows:

 

   if (dsr.size()==0 && o.Point_by_Point_Response__c ==True)

 

Any suggestions?

jd_labbejd_labbe

Figured out the problem with the code coverage. I forgot to actually set the flag that triggers the creation of the deal support record to true on the test method!!! 

 

Now at 81% coverage. Good enough for me.

 

Thanks!!

Shashikant SharmaShashikant Sharma

Just put null check condition also change your trigger to

trigger AutomateCreateDSR on Opportunity (after insert,after update) {
List<Service_Request__c> createdsr = new List <Service_Request__c> {};
List<Id> oppIds = new List<Id>{};
for (opportunity o : trigger.new) {
oppIds.add(o.id);
}


MAP<ID , List<Service_Request__c>> mapSR = new Map<ID , List<Service_Request__c>>();

List<Service_Request__c> listtempSR =  new List<Service_Request__c>();
for(Service_Request__c dsrObj :  [SELECT Id,Opportunity__c,Account__c,Name,Service_Group__c FROM Service_Request__c WHERE Opportunity__c IN :oppIds])
{
   if(mapSR.containsKey(dsrObj.Opportunity__c))
    {  
       listtempSR = mapSR.get(dsrObj.Opportunity__c);
     }
   else
    {
       listtempSR =  new List<Service_Request__c>();
    }
   
   listtempSR.add(dsrObj);
   mapSR.put(dsrObj.Opportunity__c , listtempSR);
       

}

for (opportunity o : trigger.new) 
{
    if(mapSR.contaisKey(o.id))
    {
    List<Service_Request__c> dsr = mapSR.get(o.id)
    if (dsr != null && dsr.size()==0 && o.Point_by_Point_Response__c ==True)
    {
        createdsr.add(new Service_Request__c (Opportunity__c = o.Id, Account__c=o.AccountID, Name = o.Name, Service_Group__c = 'RFx'));
    }
    }
}

    try {
    insert createdsr;
    }
    catch (Exception Ex)
    {
    system.debug(Ex);
    }
    

}

 Let me know if any issues in it.

jd_labbejd_labbe

Even though the code coverage works, I am unable to figure out the problem from my previous post with your recommended trigger. I reverted back to my trigger which works. 

 

FYI, this is just my 2nd trigger that I've built so I have a lot to learn :smileyvery-happy:

Shashikant SharmaShashikant Sharma

Gr8,

 

I would request you to mark it as solution so that others can also benifit from it.

Shashikant SharmaShashikant Sharma

Problems with you trigger 

1)SOQL in for Loop : Not a best practice as It will fail in case of Bulk Data

2)DML in fo loop , again Not a best practice as It will fail in case of Bulk Data

3) Incorrect business logic : 

 See this part of code :

for (opportunity o : trigger.new) {
oppIds.add(o.id);

{
List<Service_Request__c> dsr= [SELECT Id,Opportunity__c,Account__c,Name,Service_Group__c FROM Service_Request__c WHERE Opportunity__c IN :oppIds];

 Case , if two Opprtunities are updated then trigger.new will have two items, when the second item come in loop lis oppIds will have both the ids and your SOQL will give all the Service_Request__c for both oppurtunities , and process all the records.

 

Let me know if you did not get my point.

 

I would suggest you to go to my solution, if there are any issues in it I can help you. try with my updated trigger.

jd_labbejd_labbe

Try the updated code. No error when saving the opportunity initially. However, whenever I check the "Point by Point Response Required" box and save, it no longer creates the DSR. Not sure here.

 

Any thoughts?

Shashikant SharmaShashikant Sharma

My mistake here just misunderstood your req, you want to create a record only when record does not exists.

 

This should work properly for you.

 

trigger AutomateCreateDSR on Opportunity (after insert,after update) {
List<Service_Request__c> createdsr = new List <Service_Request__c> {};
List<Id> oppIds = new List<Id>{};
for (opportunity o : trigger.new) {
oppIds.add(o.id);
}


MAP<ID , List<Service_Request__c>> mapSR = new Map<ID , List<Service_Request__c>>();

List<Service_Request__c> listtempSR =  new List<Service_Request__c>();
for(Service_Request__c dsrObj :  [SELECT Id,Opportunity__c,Account__c,Name,Service_Group__c FROM Service_Request__c WHERE Opportunity__c IN :oppIds])
{
   if(mapSR.containsKey(dsrObj.Opportunity__c))
    {  
       listtempSR = mapSR.get(dsrObj.Opportunity__c);
     }
   else
    {
       listtempSR =  new List<Service_Request__c>();
    }
   
   listtempSR.add(dsrObj);
   mapSR.put(dsrObj.Opportunity__c , listtempSR);
       

}

for (opportunity o : trigger.new) 
{
    if ((!mapSR.contaisKey(o.id)) && o.Point_by_Point_Response__c ==True)
    {
        createdsr.add(new Service_Request__c (Opportunity__c = o.Id, Account__c=o.AccountID, Name = o.Name, Service_Group__c = 'RFx'));
    }
    
}

    try {
    insert createdsr;
    }
    catch (Exception Ex)
    {
    system.debug(Ex);
    }
    

 

This was selected as the best answer
jd_labbejd_labbe

That did it!! You are correct, my requirement was to only create a DSR when the Point by Point Response field field is checked. 

 

FYI, the "Deal Support Request" DSR record is similar to an IT help ticket, but for the business. If an account manager needed assistance with an RFP response, then he would check the box and a DSR would automatically get created and assigned to the appropriate Proposal writer for his region. Now, rather than manually creating the DSR, they would simply check a box.

 

Thanks so much!!!

jd_labbejd_labbe

Shashikant,

 

I need to figure out how to extend this trigger to accommodate additional DSRs for other groups (i.e. Technical Support, Marketing..) Use case is if the Technical Support box is checked, then a DSR is created. Assuming that there is already a DSR for System Design. Any recommendations on how to do this?

 

Thanks!!

 

 

Shashikant SharmaShashikant Sharma

Just edit this part of your trigger,

 

I have added a map mapServiceReq and used it for creatation of records

 

MAP<String,Boolean> mapServiceReq = Map<Sttring,Boolean>();
for(Service_Request__c dsrObj :  [SELECT Id,Opportunity__c,Account__c,Name,Service_Group__c FROM Service_Request__c WHERE Opportunity__c IN :oppIds])
{
   if(mapSR.containsKey(dsrObj.Opportunity__c))
    {  
       listtempSR = mapSR.get(dsrObj.Opportunity__c);
     }
   else
    {
       listtempSR =  new List<Service_Request__c>();
    }
   
   listtempSR.add(dsrObj);
   mapSR.put(dsrObj.Opportunity__c , listtempSR);
   mapServiceReq.put(dsrObj.Opportunity__c + dsrObj.Service_Group__c , true);    

}

for (opportunity o : trigger.new) 
{
    if ( (!mapServiceReq.containsKey(o.id + 'RFx') && o.Point_by_Point_Response__c ==True )
    {
      
         
       createdsr.add(new Service_Request__c (Opportunity__c = o.Id, Account__c=o.AccountID, Name = o.Name, Service_Group__c = 'RFx'));
    }

if ( (!mapServiceReq.containsKey(o.id + 'Technical Support') && o.Technical_Support_Box__c ==True )
    {
      
         
       createdsr.add(new Service_Request__c (Opportunity__c = o.Id, Account__c=o.AccountID, Name = o.Name, Service_Group__c = 'Technical Support'));
    }
    
}

 

jd_labbejd_labbe

I'm getting a compile error: unexpected token  'map' for the following line:

 

MAP<String,Boolean> mapServiceReq = Map<String,Boolean>();

 

I assume that I am using this code to replace the following, correct?

 

}

MAP<ID , List<Service_Request__c>> mapSR = new Map<ID , List<Service_Request__c>>();

List<Service_Request__c> listtempSR =  new List<Service_Request__c>();
for(Service_Request__c dsrObj :  [SELECT Id,Opportunity__c,Account__c,Name,Service_Group__c FROM Service_Request__c WHERE Opportunity__c IN :oppIds])
{
   if(mapSR.containsKey(dsrObj.Opportunity__c))
    {  
       listtempSR = mapSR.get(dsrObj.Opportunity__c);
     }
   else
    {
       listtempSR =  new List<Service_Request__c>();
    }
   
   listtempSR.add(dsrObj);
   mapSR.put(dsrObj.Opportunity__c , listtempSR);
       

}

for (opportunity o : trigger.new) 
{
    if ((!mapSR.containsKey(o.id)) && o.Point_by_Point_Response__c ==True)
    {
        createdsr.add(new Service_Request__c (Opportunity__c = o.Id, Account__c=o.AccountID, Name = o.Name, Service_Group__c = 'RFx'));
    }