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
karol.freebergkarol.freeberg 

Code coverage help needed for batch apex that send mass email.

Below is my original code and the test code. The test code only has 59% coverage. Is there anyone that can help me get that coverage up please. I know I could use some system assets but don't know for what since there are no data updates, only an email gets sent.

/**************************************************************************/
//The Opportunity Overdue Notice Emailer
//
//This class can be scheduled to run nightly to send emails to opportunity
//owners when the Est. Decision Date (CloseDate) is overdue by 14 days
//
//Emails will only be sent to opp owners that meet the following conditions:
// The opp stagename is not Closed Won or Closed Lost
// The Est. Decision Date is overdue by 14 days or more
//
/***************************************************************************/

global class OppOverdueNotice implements Schedulable{
               
              
            //mandataory function called by the Apex Scheduler
    global void execute(SchedulableContext SC) {
        sendmail(); // our main function that does the email sending
    }       //end global void execute(SchedulableContext SC

   
            //Get email addresses of people overdue opportunities by 14 days
    public List<List<ID>> getOppEmailAddresses(Date CalDate){      //(optional Integer Month, Integer Day, Integer Year)
        List<Id> mailToIds = new List<Id>();
        List<ID> WhatOppIDs = new List<ID>();
                
            //find a list of Opportuntities with overdue est decision dates
        Opportunity[] c = [SELECT Id, StageName, CloseDate, name, OwnerID
            FROM Opportunity
            WHERE CloseDate <= : CalDate
            AND StageName != 'Closed Won'
            AND StageName != 'Closed Lost'
            Limit 3
        ];
           
           
            //Loop opportunities that are overdue      
        for(Opportunity recipient : c) {
            
           
            // Take the ID of the Opp owner                                                                                   
            if (recipient.name != '') {
               
                //Check to find user record of the opp owner and get their corresponding contact record ID
                User u = [Select contact_ID__c, lastname, firstname from User where ID = : recipient.ownerID];              
               
                List <Contact> ContactRec = [Select ID, name from Contact where ID = : u.contact_id__c];
                    If (ContactRec.size() == 1) {  //We got Contact record
                        mailToIds.add(ContactRec[0].Id);   // add to email contact array
                        WhatOppIDs.add(recipient.Id);    //opportuntiy record ID
                    } Else {
                        //See if you can find the contact record using the contact name
                        List <Contact> CRec = [Select ID, name from Contact
                                where lastname = :u.lastname and firstname = :u.firstname and contact_status__c = 'User'];
                        If (CRec.size() == 1) { 
                            mailToIds.add(CRec[0].Id);   // add to email contact array
                            WhatOppIDs.add(recipient.Id);    //opportuntiy record ID
                        } //end if
                    }//end if
                             
            } else {
                System.Debug('\n*******NO Recipient');
            }  //end if else
                               
        }   //end for loop
       
        List<List<ID>> AllIDLists = New List<List<ID>>();
        AllIDLists.add(mailToIds);
        AllIdLists.add(WhatOppIDs);
            //return the list
        return AllIdLists;
           
    }//end getOppEmailAddresses()

    public void sendMail() {
            //define variables                           
        String debugAddress = 'Karol.Freeberg@newpagecorp.com';
        String OppEmailTemplateName = 'Opportunity_Past_Due_Notice';                                        
        String debugMessage;
        String[] toAddresses;

        Date CalDate = date.Today().addDays(14);
             // build the Overdue list

            //get the list of people with overdue oppotunities - this can justifiably come back empty.
        List<List<ID>> OppLists = getOppEmailAddresses(CalDate);
        If (OppLists[0].size() > 0){
           List<ID> oppIdsList = New List<ID>{OppLists.get(0).get(0)};
            List<ID> whatIdsList = New List<ID>{OppLists.get(1).get(0)};
           

            //Set the templates
            EmailTemplate oppTemplate = [select Id,Name,Subject,body
                                     from EmailTemplate where DeveloperName = :OppEmailTemplateName];
                               
            if(oppTemplate != null && oppIdsList.isEmpty() == false){
                Messaging.MassEmailMessage oppMail = new Messaging.MassEmailMessage();
                oppMail.setTargetObjectIds(oppIdsList);
                oppMail.setTemplateId(oppTemplate.Id);
                oppMail.setWhatIDs(whatIdsList);
                oppMail.setUseSignature(false);
                oppMail.setSaveAsActivity(false);

                // Send the email
                try {
                    Messaging.sendEmail(new Messaging.MassEmailMessage[] { oppMail });
                    System.Debug('Mail sent');
                }catch(Exception e){
                    System.Debug(e);
                }   // end of try catch
          
            } else {
           
                System.Debug('OppCronJob:sendMail(): Either an email template could not be found, or no opportunities are overdue');
            }//end if
        } // end If for opplists.size check

    }//end sendMail()
} // end class OppCronJob


The test code that needs help:

@isTest class OppOverdueNotice_Test {

    static testmethod void test() {
        Test.startTest();
       

       
         Date CalDate = date.Today().addDays(14);
            //Integer testday   = CalDate.day();
            //Integer testmonth = CalDate.month();
            //Integer testyear = CalDate.Year();
        OppOverdueNotice BCJ = new OppOverdueNotice();
       
        //run the test once, without ensuring that a overdue opportunity exists;
        BCJ.sendMail();
        system.debug('No email');
        
        Opportunity testOpportunity = new Opportunity();
        testOpportunity.Closedate  = date.Today().addDays(-16);
        testOpportunity.StageName  = 'Target';
        testOpportunity.Name = '2014-AARP';
        testOpportunity.reason_won_lost__C = 'Freight;History';
        testOpportunity.annual_volume__c = 3;
        testOpportunity.type = 'New Business';
        testOpportunity.tons_won__c = 15;
        testOpportunity.frequency__c = 'Spot';
        testOpportunity.End_Use__c = 'This is the end use';
        testOpportunity.start_Date__c = date.today();
       
        Contact testcontact = new contact();
        testcontact.lastname = 'Freeberg';
        testcontact.firstname = 'Karol';
        testcontact.email = 'Karol.Freeberg@newpagecorp.com';
        insert testcontact;
        Contact Crec = [Select ID from Contact where lastname = 'Freeberg'];
           
       
        //run the test again, now that a contact with an overdue opportunity existing
        insert testOpportunity;
        BCJ.sendMail();
        system.debug('Good opp email');
       
        // Schedule the test job 
   
        String CRON_EXP = '0 0 0 3 9 ? 2022';
        String jobId = System.schedule('testBasicScheduledApex', CRON_EXP, new OppOverdueNotice());
       
        // Get the information from the CronTrigger API object 
   
        CronTrigger ct = [SELECT id, CronExpression, TimesTriggered, NextFireTime
                            FROM CronTrigger
                            WHERE id = :jobId];
       
        // Verify the expressions are the same 
        System.assertEquals(CRON_EXP, ct.CronExpression);
   
        // Verify the job has not run 
        System.assertEquals(0, ct.TimesTriggered);
       
        // Verify the next time the job will run 
   
        System.assertEquals('2022-09-03 00:00:00', String.valueOf(ct.NextFireTime));
       

        Test.stopTest();
       
       

        //Clean up
        delete testOpportunity;
        delete testcontact;
       
    }
}
pconpcon
It's kind of tough to read your code (next time use the "add a code sample" button) but your issue with code coverage comes down to the fact that you need addtional tests.  The code coverage is not calculated based on System.asserts but on the actual lines of code run.  For your code I would suggest adding additional test methods that go into your if statements.  For example, directly testing getOppEmailAddresses and testing for a blank recipient name.  Then an additional test where the contact is not found by id and so forth.  Continue these types of tests to cover all of the corner cases inside your class.

NOTE: You do not need to clean up your test data, the testing framework will handle that for you.