+ Start a Discussion
FranchisingGuruFranchisingGuru 

Trigger Coverage Fails on Deployment - HELP...SALES PROCESSES STALLED

I don't know what happened, but I had several triggers working previously, and now I can't even deploy previous triggers that used to be working in production.  The first trigger and class is below.. I think there is something wrong with my test class that is not making the trigger fire (test coverage is 100% in sandbox). Perhaps this causing the code coverage upon deployment to be 0%.... PLEASE HELP.

 

THIS IS MY TRIGGER THAT WORKS IN SANDBOX

 

trigger statusChangeAutoEmail on Lead (after update) {
List<Messaging.SingleEmailMessage> messages = new List<Messaging.SingleEmailMessage>();
List<Lead> leadsToUpdate=new List<Lead>();

List<Lead> leadList= [select Id, Email,X1st_Attempt_Email__c,X2nd_Attempt_Email__c, 
    Closed_Lost_Email__c, Status,Franchise_Concept__c, Owner.Name,Owner.Email from Lead 
    where International__c=false AND No_Auto_Email__c=false AND EmailBouncedReason=NULL AND
    (Status!='New Lead' or Status!='Qualified')]; 

for(Lead leadEmail : leadList) {
       
        if(leadEmail.Status == '1st Attempt' && leadEmail.X1st_Attempt_Email__c==false
        ) {       
            //send Email
            String template = ''; // initialize variable to hold template name filled in below           
            template = 'Standard Auto Sales Appt Reminder Email';
           
            Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
            message.setTemplateId([select id from EmailTemplate where Name = :template].id);
            message.setTargetObjectId(leadEmail.id);
           
            // String to hold the email addresses to which the email is being sent. 
            message.setToAddresses (new String[] {leadEmail.Email});
            
            message.setsaveAsActivity(true);
            message.setsenderDisplayName(leadEmail.Owner.Name);
            message.setreplyTo(leadEmail.Owner.Email);

            // Add the e-mail to the list to be sent
            messages.add(message);
            
            //update to Lead so email only sent once
            leadEmail.X1st_Attempt_Email__c=true;
            leadsToUpdate.add(leadEmail);
            
        }            
                    
        
        else if(leadEmail.Status == '2nd Attempt' && leadEmail.X2nd_Attempt_Email__c==false
        ) {       
            //send Email
            String template = ''; // initialize variable to hold template name filled in below           
            template = 'Standard Auto Sales Appt Reminder Email';
           
            Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
            message.setTemplateId([select id from EmailTemplate where Name = :template].id);
            message.setTargetObjectId(leadEmail.id);
           
            // String to hold the email addresses to which the email is being sent. 
            message.setToAddresses (new String[] {leadEmail.Email});
            
            message.setsaveAsActivity(true);
            message.setsenderDisplayName(leadEmail.Owner.Name);
            message.setreplyTo(leadEmail.Owner.Email);

            // Add the e-mail to the list to be sent
            messages.add(message);
            
            //update to Lead so email only sent once
            leadEmail.X2nd_Attempt_Email__c=true;
            leadsToUpdate.add(leadEmail);
                      
        }

        else if(leadEmail.Status == 'Closed - Lost' && leadEmail.Closed_Lost_Email__c==false
        ) {       
            //send Email
            String template = ''; // initialize variable to hold template name filled in below           
            template = 'Standard Auto Sales Appt Reminder Email';
           
            Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
            message.setTemplateId([select id from EmailTemplate where Name = :template].id);
            message.setTargetObjectId(leadEmail.id);
           
            // String to hold the email addresses to which the email is being sent. 
            message.setToAddresses (new String[] {leadEmail.Email});
            
            message.setsaveAsActivity(true);
            message.setsenderDisplayName(leadEmail.Owner.Name);
            message.setreplyTo(leadEmail.Owner.Email);

            // Add the e-mail to the list to be sent
            messages.add(message);
            
            //update to Lead so email only sent once
            leadEmail.Closed_Lost_Email__c=true;
            leadsToUpdate.add(leadEmail);
                        
        }                     
        
        else{
        }
    }  //end for statement      
        Messaging.sendEmail(messages);
        update leadsToUpdate;    
} //end trigger

 

THIS IS MY TEST CLASS

 

@isTest
private class statusChangeAutoEmail {

    static testMethod void statusChangeAutoEmail() {

    List<Messaging.SingleEmailMessage> messages = new List<Messaging.SingleEmailMessage>();
    List<Lead> leadsToUpdate=new List<Lead>();
    
    
    Lead[] leadsToCreate=new Lead[]{};
    for(Integer x=0; x<20; x++){
        Lead ld = new Lead(lastname='test', Status='1st Attempt', email='test@testing.com',company='test');
        leadsToCreate.add(ld);
    }    

    for(Integer x=0; x<20; x++){
        Lead ld = new Lead(lastname='test', Status='2nd Attempt', email='test@testing.com',company='test');
        leadsToCreate.add(ld);
    }

    for(Integer x=0; x<20; x++){
        Lead ld = new Lead(lastname='test', Status='Closed - Lost', email='test@testing.com',company='test',
        Closed_Lost_Dispositions__c='Other');
        leadsToCreate.add(ld);
    }    
        

    //Now for the test...
    Test.startTest();
    insert leadsToCreate;
    Messaging.sendEmail(messages);
    Test.stopTest();
        
        
        
    }
}

 

I'm pretty frantic at this point, since our sales team relies on several of these triggers that used to work... Help would be MOST APPRECIATED

 

-Amanda

Best Answer chosen by Admin (Salesforce Developers) 
krishnagkrishnag

instead of using lists use Map and sets automatically the trigger handles bulk data and also one more option is to go for asynchronous class using a future method,

All Answers

grigri9grigri9

Your trigger is only running on update and in your test you are only inserting the leads.

FranchisingGuruFranchisingGuru

Oh my goodness!! Is that all that's wrong? So, if I insert the test leads then update them in the testing section, you think that will solve the problem?  Also, I'm wondering if my trigger is "bulkified". Any thoughts?

 

Thank you so much! I have been up all night trying to get everything reverted back.  I'll mark this as solved after I try the changes.

krishnagkrishnag

instead of using lists use Map and sets automatically the trigger handles bulk data and also one more option is to go for asynchronous class using a future method,

This was selected as the best answer
grigri9grigri9

I can see a couple of possible issues in your trigger.

 

1. You might be causing an infinite loop because you are updating leads in a lead update trigger. Your query doesn't seem to be filtering to exclude leads where you updated the attempt_email fields so the trigger might run on those leads over and over.

 

2. You are querying the template id inside your for loop so if you process more than 20 leads at a time you'll hit the governor limit for soql queries in a trigger.

FranchisingGuruFranchisingGuru

You are unbelievably quick and it couldn't be any more appreciated right now. I have one ear on the phone with salesforce support, while trying to make these changes.  I changed my test class to update the lead list, and I still cannot deploy.

 

I'm sorry I'm such an amateur, but could you please give me a starting point on how to modify my trigger to include sets and maps? I want to do everything correctly this time so this doesn't happen again, since I think I deployed faulty classes/triggers previously. Aaahh!!

FranchisingGuruFranchisingGuru

Thank you for your reply!  I'm amazed by the feedback here. I wish I had gotten on here sooner!!

 

I did exclude the query for template Id, as I figured that was probably an issue.

 

As for your first point, do you think I should include something in the where clause to say something like 'attempt_email != true'.  Is that what you mean by excluding them after update?

 

Thanks again!!

grigri9grigri9

The Apex code Developer's Guide has a pretty good introduction to writing bulk triggers. When you run your test on sandbox or try to deploy it should tell you what error prevented the trigger from running/deploying successfully.

FranchisingGuruFranchisingGuru

Thanks for the link. My error message when testing ddeployment in Eclipse is that pretty much every line in the trigger is not tested even from line 2 (how is that possible)...  I'm so completely lost again although I  thought I was making headway.

 

Is this still mostly a problem with my test class not initiating the trigger?

 

P.S. I want to crawl in the fetal position right now and just hide under my desk until this fixes itself. :)

grigri9grigri9

Can you post your new test code and the last lines of the debug log. I.E. where it either exits the testmethod or throws an exception. Also, maybe I don't understand your business logic but do you really want to send an email to every lead that matches your query when any lead is updated? Wouldn't you just want to send emails to the leads that were updated?

FranchisingGuruFranchisingGuru

Okay, sorry. Now of course my computer and Eclipse are temporarily freezing. I guess they're as tired as I am :) I have the last bit of debug code from the failure (didn't know how much was needed). It doesn't seem to fail. As for the business logic, yes, I would only want to send an email to those updated, but it's my Apex logic that I can figure out..  How  would I specify to send only to those updated leads? 

 

//ERRORS FROM DEPLOYMENT (also doesn't test all the lines, especially those within the first two conditional statements-I don't know why it decides to test only the last conditional statement when status='Closed - Lost')

 

# Test Results:

Run Failures:
  statusChangeAutoEmail.statusChangeAutoEmail System.LimitException: Apex heap size too large: 2185444

 

 

//TEST CLASS

 

@isTest
private class statusChangeAutoEmail {

    static testMethod void statusChangeAutoEmail() {

    List<Messaging.SingleEmailMessage> messages = new List<Messaging.SingleEmailMessage>();
    List<Lead> leadsToUpdate=new List<Lead>();
    
    
    Lead[] leadsToCreate1=new Lead[]{};
    Lead[] leadsToCreate2=new Lead[]{};
    Lead[] leadsToCreate3=new Lead[]{};           
    for(Integer x=0; x<10; x++){
        Lead ld = new Lead(lastname='test', Status='New Lead', email='test@testing.com',company='test');
        leadsToCreate1.add(ld);
    }    

    
    for(Integer x=0; x<10; x++){
        Lead ld = new Lead(lastname='test', Status='1st Attempt', email='test@testing.com',company='test');
        leadsToCreate2.add(ld);
    }    

    for(Integer x=0; x<10; x++){
        Lead ld = new Lead(lastname='test', Status='2nd Attempt', email='test@testing.com',company='test');
        leadsToCreate3.add(ld);
    }
/*
    for(Integer x=0; x<20; x++){
        Lead ld = new Lead(lastname='test', Status='Closed - Lost', email='test@testing.com',company='test',
        Closed_Lost_Dispositions__c='Other');
        leadsToCreate4.add(ld);
    }  
*/  
    insert leadsToCreate1;        
    insert leadsToCreate2;            
    insert leadsToCreate3;                   
    
    //Now for the test...
    Test.startTest();
    for(Lead l:leadsToCreate1){
    l.Status='1st Attempt';
    leadsToUpdate.add(l);
    }
    
    for(Lead l:leadsToCreate2){
    l.Status='2nd Attempt';
    leadsToUpdate.add(l);
    }

    for(Lead l:leadsToCreate3){
    l.Status='Closed - Lost';
    l.Closed_Lost_Dispositions__c='Other';
    leadsToUpdate.add(l);
    }
        
    update leadsToUpdate;
    Messaging.sendEmail(messages);
    Test.stopTest();
        
        
        
    }
}

Long day...

 

FranchisingGuruFranchisingGuru

YES!!!  This is what did the trick. I used a set to first gather all the unique ids in the trigger, then populated a list with the query on the leads whose Ids were in the set (along with my other necessary criteria).

 

Thank you for pointing me in the right direction!! 100% coverage with my test class and trigger coverage. Now, I'm having fun again and will work on more triggers. Thanks everyone!