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
Jamal ArogundadeJamal Arogundade 

The execute method in my apex batch job is not being covered. Please can anyone advice?

Batch job class:
public class Renewal_job implements Database.Batchable<SObject> {
    //public Renewal_job() {
    
    //}
    public Database.QueryLocator start(Database.BatchableContext bc){
        // TODO: the query below to only extract the memberships that we need to work on
        
        return Database.getQueryLocator([select id, name, membership_status__c, recordtype.name, regular_payment__c, member_1__c, expiry_date__c, consessionary__c, Discount__c, Next_Renewal_Date__c from membership__c where (Next_Renewal_Date__c <= TODAY  or expiry_date__c <= TODAY )and successor_membership__c = NULL]); // TODO: Add extra filters
    }
    
    public void execute(Database.BatchableContext bc, list<membership__c> scope){
        id renewal_opp_record_type = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('Membership').getRecordTypeId();
        id renewal_camp_record_type = Schema.SObjectType.Campaign.getRecordTypeInfosByName().get('Renewal').getRecordTypeId();
        campaign renewal_campaign = [select id, name, StartDate,EndDate from campaign where recordtype.name = 'Renewal' and startdate <= TODAY  and enddate >= TODAY Order by startdate asc limit 1]; // TODO: Sort out this query
        if (renewal_campaign.id == NULL){
            // TODO: Add consent statement - Fix name. Not sure what else to be honest 
            Consent_statement__c consent_statement = new Consent_statement__c(name = 'Consent', Used_from__c = date.today(), Valid_consent_statement__c = TRUE, Consent_statement_text__c = 'Read' );
            insert consent_statement;
            renewal_campaign = new campaign(name='Renewals ' + string.valueof(date.today().month()) + ' ' + string.valueof(date.today().year()), recordtypeid=renewal_camp_record_type, startdate=date.today(), enddate=date.today().addMonths(1), isactive=True, Status='In progress');
            insert renewal_campaign;
            // TODO: Add a task to finish updating records assign to membership team queue?
            Group g = [Select Id from Group where Type = 'Task' AND NAME = 'Membership Team Queue'];
            //QueueSobject mappingObject = new QueueSobject(QueueId = g.Id, SobjectType = 'Membership__c');
            //insert mappingObject;
            ID qID = g.ID;      
            Task t = new Task();
            t.Subject = 'Other';
            t.Priority = 'Normal';
            t.Status = 'Not Started';
            t.OwnerId = qID;
            insert t;  
        }
        set<id> current_renewal_opps_ids = new set<id>();
        for (membership__c mem : scope){
           
            if (mem.Next_Payment__c != NULL){
                current_renewal_opps_ids.add(mem.Next_Payment__c);
            }
        }
        List<Membership_Amount_Line__c> mal = ramblersUtility.get_renewal_lookup(NULL, NULL);
        list<membership__c> mems_to_update = new list<membership__c>();
        list<CampaignMember> add_campaign_members = new list<campaignMember>();
        list<opportunity> opps_to_add = new List<Opportunity>();
        list<opportunity> opps_to_update = new List<Opportunity>();
        map<id, opportunity> existing_renewal_opps = new map<id, Opportunity>([select id, stagename, name, linked_membership__c from Opportunity where linked_membership__c = :current_renewal_opps_ids]);
        for (sobject s_mem : scope){
            membership__c mem = (membership__c)s_mem;
            decimal rebate_percentage = NULL;
            decimal rebate_cash = NULL;
            if (mem.Discount__r.Discount_renews__c){
                rebate_percentage = mem.discount__r.Discount_percentage__c;
                rebate_cash = mem.discount__r.Discount_amount__c;
            } else {
                mem.Discount__c = NULL; // If the rebate does not renew clear it from the membership.
            }
            
            
            if(Date.today() >= mem.Expiry_Date__c){
                // Update status for lapsed/inactive - I think we should update the name as well
                if (date.today().addMonths(-3) <= mem.Expiry_Date__c){
                    mem.Membership_Status__c = 'Payment pending';
                } else if (date.today().addMonths(-15) <= mem.Expiry_Date__c){
                    mem.Membership_Status__c = 'Lapsed';
                    if (!mem.Next_Payment__r.IsClosed){
                        // Close off the opportunity
                        existing_renewal_opps.get(mem.Next_Payment__c).StageName = 'Closed Lost';
                        opps_to_update.add(existing_renewal_opps.get(mem.next_payment__c));
                    }
                } else {
                    mem.Membership_Status__c = 'Inactive';
                }
                mems_to_update.add(mem);
            } else if (mem.Next_Renewal_Date__c <= Date.today()){
                // These records need to be renewed add them to the renewal campaign
                if (mem.recordtype.name == 'Life'){
                    // They are a life member - Add to campaign with correct status (essentially new card only)
                    // add_campaign_members.add(new CampaignMember(CampaignId=renewal_campaign, ContactId=mem.Member_1__c, Status='To Renew', ));
                }
                if (mem.regular_payment__c != NULL){
                    // Calculate membership amount. If it is 0 then we just add them with a new card
                    if (ramblersutility.get_membership_amount(mal, mem.Expiry_Date__c, mem.consessionary__c, mem.Regular_Payment__r.npe03__Installment_Period__c, mem.membership_type__c, mem.recordtype.name, mem.regular_payment__r.npsp4hub__Payment_Method__c, rebate_percentage, rebate_cash) == 0){
                        // Just send them a new card
                        //add_campaign_members.add(new CampaignMember());
                    } else {
                        // Send them details of new direct debit amount. No need to update the amount just yet. Need to wait until there are no further payments before the expiry date before we change the pricing
                        //add_campaign_members.add(new CampaignMember());
                    }
                } else {
                    // We need to create and insert the renewal opportunity
                    opps_to_add.add(new Opportunity(name='s', CloseDate=mem.Expiry_Date__c, Membership_Amount__c=ramblersutility.get_membership_amount(mal, mem.Expiry_Date__c, mem.consessionary__c, 'Annual', mem.Membership_Type__c, mem.recordtype.name, 'Cash', rebate_percentage, rebate_cash), accountid=mem.Member_1__r.AccountId, npsp__Primary_Contact__c=mem.member_1__c, StageName='Pledged', Discount__c = mem.Discount__c)); // TODO: Decide what stage this should be at
                    //add_campaign_members.add(new CampaignMember());
                }
                try{
                    mem.Next_Renewal_Date__c = mem.Next_Renewal_Date__c.addYears(1); // Update the renewal date
                } catch(Exception e){
                    mem.Next_Renewal_Date__c = mem.Next_Renewal_Date__c.adddays(365); // Inserted to account for leap years - I don't think it is absolutely necessary, but we may as well put it in
                }
                mems_to_update.add(mem);
            } else {
                // I don't think we need to do anything - But leave in place in case we do
            }
        }
        insert opps_to_add;
        update opps_to_update;
        set<id> opp_ids = new set<id>();
        for (opportunity o : opps_to_add){
            opp_ids.add(o.id);
        }
        List<Opportunity> opps = [select id, name, linked_membership__c from Opportunity where id =: opp_ids];
        insert add_campaign_members;
        // Now loop back through and back fill any links to new opportunities
        for (membership__c mem : mems_to_update){
            //membership__c mem = (membership__c)s_mem;
            if (mem.Next_Renewal_Date__c <= Date.today() && Date.today() < mem.Expiry_Date__c && mem.recordtype.name != 'Life' && mem.Regular_Payment__c == NULL){
                for (Opportunity o : opps){
                    if (o.linked_membership__c == mem.id){
                        mem.Next_Payment__c = o.id;
                        break;
                    }
                }
            }
            
        }
        update mems_to_update;
    }
    
    public void finish(Database.BatchableContext bc){
        system.debug('Completed Renewals');
        // TODO: add notifications 
        // Get the ID of the AsyncApexJob representing this batch job
        // from Database.BatchableContext.
        // Query the AsyncApexJob object to retrieve the current job's information.
       List<Group> GroupId =  [Select Id from Group where type='Queue' and Name='Membership Team Queue'];
       list<GroupMember> userIdList = [Select UserOrGroupId From GroupMember where GroupId =:GroupId];
        Set<ID> useridset = new Set<ID>();
        for (GroupMember gm : userIdList ){
           useridset.add(gm.UserOrGroupId);
        }
        
        list<User> user = [SELECT Id, Email FROM USER WHERE ID IN: useridset];
        List<String> emaillist = new List<String>();
        for (User u : user){
            emaillist.add(u.Email);
        }
        
        AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
                          TotalJobItems, CreatedBy.Email
                          FROM AsyncApexJob WHERE Id =
                          :BC.getJobId()];
        // Send an email to the Apex job's submitter notifying of job completion.
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {a.CreatedBy.Email};
            toAddresses.addAll(emaillist);
            mail.setToAddresses(toAddresses);
        mail.setSubject('Batch job status ' + a.Status);
        mail.setPlainTextBody
            ('The batch Apex job processed ' + a.TotalJobItems +
             ' batches with '+ a.NumberOfErrors + ' failures.');
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
        
        
    }
}



Batch Test class:

@isTest
private class RenewalJobBatchTest {
    static testMethod void RenewalBatchTestMethod(){
        // Just in case pull trigger handlers for npsp triggers
        List<npsp__Trigger_Handler__c> triggerHandlers = npsp.TDTM_Config_API.getCachedRecords();
        //set up test data
        list<Contact> con = new list<Contact>();
        for (Integer i = 0; i < 20; i++){
            con.add(new Contact(lastName = 'test lastname ' + string.valueof(i), MailingStreet = 'test mailingstreet'));
        }
        insert con;
        list <npe03__Recurring_Donation__c> rc = new list <npe03__Recurring_Donation__c> ();
        for (Integer i = 0; i < 20; i ++){
            rc.add(new npe03__Recurring_Donation__c (npe03__Contact__c = con[0].id, npsp4hub__Payment_Method__c = 'Direct Debit', npe03__Installment_Period__c = 'Monthly', Top_up_Amount__c = 10, npe03__Open_Ended_Status__c = 'Open', npe03__Date_Established__c = date.today()) );
        }
        
        insert rc;
        Membership_Amount__c ma = new Membership_Amount__c(Name = 'Select Membership', Start_date__c = Date.today().addDays(-45) , End_date__c = Date.today().addDays(50) );
        insert ma;
        List<Membership_Amount_Line__c> malineitem = [SELECT id, Amount__c FROM Membership_Amount_Line__c WHERE Membership_Amount__c =: ma.Id];
        Decimal dec = 1.0;
        for (Membership_Amount_Line__c lineitem : malineitem){
            lineitem.Amount__c = dec;
            dec += 2.1;
        }
        
        update malineitem;
        list <Opportunity> opps = new list<Opportunity>();
        for (Integer i = 0; i < 20; i++){
            opps.add(new Opportunity(Amount = 10.00, Name = 'test name', stageName = 'Closed Won', CloseDate = date.today()));
        }
        insert opps;
        
        Discount__c discount_hundred = new Discount__c (name = '100% discount', Discount_percentage__c = 100, Discount_renews__c = TRUE);
        insert discount_hundred;
        system.debug('line 36');
        id life_membership_type = Schema.SObjectType.Membership__c.getRecordTypeInfosByName().get('Life Membership').getRecordTypeId();
        
        list<Membership__c> membership = new list<Membership__c> ();
        membership.add(new Membership__c(Member_1__c = con[0].id , Membership_Status__c = 'Active', Membership_type__c = 'Individual', Start_Date__c = Date.today(), Next_Renewal_Date__c = date.today().addMonths(-11), regular_payment__c = rc[0].id, consessionary__c = TRUE, expiry_date__c = Date.valueOf('2020-07-29')));
        membership.add(new Membership__c(Member_1__c = con[1].id , Membership_Status__c = 'Active', Membership_type__c = 'Individual', Start_Date__c = Date.today(), Next_Renewal_Date__c = date.today().addMonths(-11), Next_Payment__c = opps[0].id,regular_payment__c = null, consessionary__c = TRUE, expiry_date__c = Date.today().addMonths(-15)));
        membership.add(new Membership__c(Member_1__c = con[2].id , Membership_Status__c = 'Active', Membership_type__c = 'Individual', Start_Date__c = Date.today(), Next_Renewal_Date__c = date.today().addMonths(-11), regular_payment__c = rc[1].id, consessionary__c = TRUE, expiry_date__c = Date.today().addYears(-5)));
        membership.add(new Membership__c(Member_1__c = con[3].id , Membership_Status__c = 'Active', Membership_type__c = 'Individual', Start_Date__c = Date.today(), Next_Renewal_Date__c = date.today().addMonths(-11), regular_payment__c = null, consessionary__c = TRUE, expiry_date__c = null, last_payment__c = opps[1].id, RecordTypeId = life_membership_type));
        membership.add(new Membership__c(Member_1__c = con[4].id , Membership_Status__c = 'Active', Membership_type__c = 'Individual', Start_Date__c = Date.today(), Next_Renewal_Date__c = date.today().addMonths(-11), regular_payment__c = rc[2].id, consessionary__c = TRUE, expiry_date__c = date.today().addmonths(2), last_payment__c = null, Discount__c = discount_hundred.id));
        membership.add(new Membership__c(Member_1__c = con[5].id , Membership_Status__c = 'Active', Membership_type__c = 'Individual', Start_Date__c = Date.today(), Next_Renewal_Date__c = date.today().addMonths(-11), regular_payment__c = rc[3].id, consessionary__c = TRUE, expiry_date__c = date.today().addmonths(2), last_payment__c = null));
        membership.add(new Membership__c(Member_1__c = con[6].id , Membership_Status__c = 'Active', Membership_type__c = 'Individual', Start_Date__c = Date.today(), Next_Renewal_Date__c = date.today().addMonths(-11), regular_payment__c = rc[4].id, consessionary__c = TRUE, expiry_date__c = date.today().addmonths(2), last_payment__c = opps[1].id));
        
        insert membership;
        
        Test.startTest();
        Renewal_job ren = new Renewal_job();
        Database.executeBatch(ren);
           list<campaign> all_camps = [select id from campaign where recordtype.name = 'Renewal'];
           system.debug(all_camps.size());
        //system.assert(all_camps.size() == 1); // TODO: Get data and run tests.
        Test.stopTest();
        
    }
}
AnudeepAnudeep (Salesforce Developers) 
Hi Jamal, 

It appears that the query in the start method is not returning any records based on the membership__c data inserted in the class. Can you check if your membership__c records have Next_Renewal_Date__c <= TODAY, expiry_date__c <= TODAY  and successor_membership__c = NULL
 
select id, name, membership_status__c, recordtype.name, regular_payment__c, member_1__c, expiry_date__c, consessionary__c, Discount__c, Next_Renewal_Date__c from membership__c where (Next_Renewal_Date__c <= TODAY  or expiry_date__c <= TODAY )and successor_membership__c = NULL

Also, try invoking the batch as described here

Anudeep
Jamal ArogundadeJamal Arogundade
Hi Anudeep,

I have ran the query - select id, name, membership_status__c, recordtype.name, regular_payment__c, member_1__c, expiry_date__c, consessionary__c, Discount__c, Next_Renewal_Date__c from membership__c where (Next_Renewal_Date__c <= TODAY  or expiry_date__c <= TODAY )and successor_membership__c = NULL 
and i have two results. 
Jamal ArogundadeJamal Arogundade
in the link you shared it says ContactBatch cb = New ContactBatch(); Database.QueryLocator ql = cb.start(null); cb.execute(null,YOURLISTOFRECORDS); cb.Finish(null);

in my case what would be my YOURLISTOFRECORDS

thanks