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
Cris9931Cris9931 

Test class question for schedule apex

Hi, can anyone give me some feedback at how can I cover these lines of code in my test class?

for(SVMXC__Service_Order_Line__c wd : workDetails)  
            {  
                String key = '' + wd.SVMXC__Group_Member__r.SVMXC__Salesforce_User__c + wd.SVMXC__Start_Date_and_Time__c.date();  
                SVMXC__Timesheet_Day_Entry__c tde = dayEntries.get(key);  
                if(tde != null)   
                {   
                   SVMXC__Timesheet_Entry__c timeEntry = new SVMXC__Timesheet_Entry__c(); 
                   timeEntry.SVMXC__Timesheet__c = tde.SVMXC__Timesheet__c;   
                   timeEntry.SVMXC__Timesheet_Day__c = tde.Id;   
                   timeEntry.SVMXC__Work_Detail__c = wd.Id;   
                   timeEntry.SVMXC__Start_Time__c = wd.SVMXC__Start_Date_and_Time__c;   
                   timeEntry.SVMXC__End_Time__c = wd.SVMXC__End_Date_and_Time__c;   
                   timeEntry.SVMXC__Comments__c = wd.SIG_Activity_type__c;   
                   timeEntry.SIG_Is_Billable__c  = true;         
                   timeEntry.SVMXC__Account__c  = wd.SIG_Ship_To__c;         
                   timeEntry.SVMXC__Duration__c = wd.SVMX_Duration__c / 60;   
                   timeEntries.add(timeEntry);  
                }
From line 2 above the code is red and is not covered and I can't understand how to cover it.
Best Answer chosen by Cris9931
Cris9931Cris9931

Found the solution:

I had to put @isTest (SeeAllData = true) because the records were on Private mode for the object! Crazy.

All Answers

Cris9931Cris9931

Found the solution:

I had to put @isTest (SeeAllData = true) because the records were on Private mode for the object! Crazy.

This was selected as the best answer
Ashish Singh SFDCAshish Singh SFDC
Hi Cris9931,

I would recommend not to use @isTest(SeeAllData =true) as this is not the Best Practice. Click here to read Apex Documentation for seeAllData (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_seealldata_using.htm)

Instead you can create a test record in your test class and then use that record your test class. For this purpose you can levearage:

@testSetup static void methodName() {
 
}

 Click here to read more about one time test record setup (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_testsetup.htm)

I would recommend to follow  Test Classes (https://trailhead.salesforce.com/content/learn/modules/apex_testing/apex_testing_data) module to get good understanding of test class and you'll easily understand it.

Thanks,
Ashish Singh.
Cris9931Cris9931

Hi Ashish,

Thanks for that.. Now I have another issue on the same class, the test class runs perfectly I have 100% but when I try to migrate to prod I have this error:

System.LimitException: Too many query rows: 50001
Stack Trace: Class.Database.QueryLocatorIterator.hasNext: line 41, column 1 Class.scheduledBatchTimeEntryForWorkDetail.execute: line 13, column 1


User-added image

 

Do I need to re-write that query?

Ashish Singh SFDCAshish Singh SFDC
Hi Cris9931,

The reason why you got this error because you still have seeAllData = true in your test class. That why it's not a good practice. It will simply query all the records and clearly exceed 50000 records if criteria matches with SOQL.

Secondly, Do you want to do Bulk Processing? If that is the case then you should go with Batch Apex and then schedule that Batch Apex with Apex Scheduler. Otherwise, you'll keep getting this error whenever you have more than 50000 records.


As a workaround if you LIMIT Query by 50000, you'll be able to prevent from the Error.

But a good solution should follow the step mentioned in Bold.

Thanks,
Ashish Singh.
Cris9931Cris9931

I've transformed in a batch class:

 

global class scheduledBatchTimeEntryForWorkDetail implements Schedulable, Database.Batchable<sObject>
    {
       global Database.QueryLocator start(Database.BatchableContext bc) 
       {
        DateTime refDate = DateTime.Now();
        DateTime EndDateInterval =  refDate.AddDays(-180);
        return Database.getQueryLocator(
            'SELECT Id, SVMXC__Group_Member__r.SVMXC__Salesforce_User__c,SIG_Activity_type__c, SIG_Ship_To__c, SVMXC__Start_Date_and_Time__c, SVMXC__End_Date_and_Time__c,SVMX_Duration__c, SVMXC__Line_Type__c, (SELECT Id FROM SVMXC__Time_Entrys__r) ' + 
            'FROM SVMXC__Service_Order_Line__c ' +
            'WHERE (SVMXC__Line_Type__c=\'Labor\' OR SVMXC__Line_Type__c=\'Travel\') AND SVMXC__Group_Member__c!=null AND SVMXC__Line_Status__c = \'Processed\' AND SVMXC__Start_Date_and_Time__c <= :refDate AND SVMXC__Start_Date_and_Time__c >= :EndDateInterval'
        );
       }
    global void execute(Database.BatchableContext bc, List<SVMXC__Service_Order_Line__c> scope)
    {
        List<SVMXC__Service_Order_Line__c> wl = new List<SVMXC__Service_Order_Line__c>(); 
        Set<Id> techIds = new Set<Id>();
        
     	for(SVMXC__Service_Order_Line__c workdetails :scope){
            if(workdetails.SVMXC__Time_Entrys__r.size() == 0) 
                {   
                    wl.add(workdetails);   
                    techIds.add(workdetails.SVMXC__Group_Member__r.SVMXC__Salesforce_User__c);  
                } 
        }
        
        Map<String, SVMXC__Timesheet_Day_Entry__c> dayEntries = new Map<String, SVMXC__Timesheet_Day_Entry__c>(); 
     
            for(SVMXC__Timesheet_Day_Entry__c tde : [SELECT Id, SVMXC__Timesheet__c, SVMXC__Timesheet__r.SVMXC__User__c, SVMXC__Timsheet_Day__c FROM SVMXC__Timesheet_Day_Entry__c WHERE SVMXC__Timesheet__r.SVMXC__User__c IN :techIds]) 
            {  
                String key = '' + tde.SVMXC__Timesheet__r.SVMXC__User__c + tde.SVMXC__Timsheet_Day__c;
                dayEntries.put(key, tde); 
            }
        
         List<SVMXC__Timesheet_Entry__c> timeEntries = new List<SVMXC__Timesheet_Entry__c>(); 
    
            for(SVMXC__Service_Order_Line__c wd : wl)  
            {  
                String key = '' + wd.SVMXC__Group_Member__r.SVMXC__Salesforce_User__c + wd.SVMXC__Start_Date_and_Time__c.date();  
                SVMXC__Timesheet_Day_Entry__c tde = dayEntries.get(key);  
                if(tde != null)   
                {   
                   SVMXC__Timesheet_Entry__c timeEntry = new SVMXC__Timesheet_Entry__c(); 
                   timeEntry.SVMXC__Timesheet__c = tde.SVMXC__Timesheet__c;   
                   timeEntry.SVMXC__Timesheet_Day__c = tde.Id;   
                   timeEntry.SVMXC__Work_Detail__c = wd.Id;   
                   timeEntry.SVMXC__Start_Time__c = wd.SVMXC__Start_Date_and_Time__c;   
                   timeEntry.SVMXC__End_Time__c = wd.SVMXC__End_Date_and_Time__c;   
                   timeEntry.SVMXC__Comments__c = wd.SIG_Activity_type__c;   
                   timeEntry.SIG_Is_Billable__c  = true;         
                   timeEntry.SVMXC__Account__c  = wd.SIG_Ship_To__c;         
                   timeEntry.SVMXC__Duration__c = wd.SVMX_Duration__c / 60;   
                   timeEntries.add(timeEntry);  
                } 
            } 
     
    System.debug('### timeEntries : ' + timeEntries.size()); 
     
            if(timeEntries.size() > 0)  
                insert timeEntries;
    }    
    global void finish(Database.BatchableContext bc){
        // execute any post-processing operations that are needed
    }    
         global void execute(SchedulableContext SC) {
        System.debug('Work Detail handler: Schedule Batch execution started');   
        Integer intBatchSize = 10;
        scheduledBatchTimeEntryForWorkDetail wlHanlder  = new scheduledBatchTimeEntryForWorkDetail();
        Database.executebatch(wlHanlder, intBatchSize);
        System.debug('WorkOrder Email handler: Schedule Batch execution done');
    }
    }

Is this the right approach?

 

My test class:

I have 100% code coverage with this.

@isTest 
public class scheduledBatchTimeEntryForWorkDetail_UT
{
    
    @isTest
    public static  void testTimeEntryCreation()
    {
        Profile fsmProf = [SELECT Id FROM Profile WHERE Name='SIG-FSM-Field Service Engineer' limit 1];
        User fsmUser = new User(Alias = 'testfsm1', Email='testfsm1@test.com', 
                                EmailEncodingKey='UTF-8', LastName='TestFSM1', LanguageLocaleKey='en_US', 
                                LocaleSidKey='en_US', ProfileId = fsmProf.Id, 
                                TimeZoneSidKey='America/Los_Angeles', UserName='testfsm1@test.com',
                                SIG_Ticket_Recipient__c = 'AM-N - FSE', isActive=true, SIG_Is_User_Authorized__c = true);
        insert fsmUser;
        
        SVMXC__Service_Group__c serviceTeam = new SVMXC__Service_Group__c();
        serviceTeam.SVMXC__Active__c = True;
        serviceTeam.Name = 'Test Service Group';
        insert serviceTeam;
        
        SVMXC__Service_Group_Members__c tech = new SVMXC__Service_Group_Members__c();
        tech.Name='Test Tech';
        tech.SVMXC__Service_Group__c = serviceTeam.id;
        tech.SVMXC__Salesforce_User__c = fsmUser.Id;
        insert tech;
       
        
        //insert work order
        SVMXC__Service_Order__c  workOrder = new SVMXC__Service_Order__c ();
        workOrder.SVMXC__Order_Status__c  = 'Open';
        workOrder.SVMXC__Sub_Status__c = 'Unresolved';
        workOrder.SVMXC__Priority__c = 'Low';
        workOrder.SVMXC__Order_Type__c = 'Reactive';
        workOrder.SVMXC__Group_Member__c  = tech.Id;
        insert workOrder; 

                 //insert timesheet
        SVMXC__Timesheet__c weekelyTimeEntries = new SVMXC__Timesheet__c();
        weekelyTimeEntries.SIG_Timesheet_Technician__c =   tech.Id;
        weekelyTimeEntries.SVMXC__Start_Date__c = System.Today();
        weekelyTimeEntries.SVMXC__User__c = fsmUser.Id;
        insert weekelyTimeEntries;
        
          
        //insert dailyEntries
        SVMXC__Timesheet_Day_Entry__c dayEntries = new SVMXC__Timesheet_Day_Entry__c();
        dayEntries.SVMXC__Timesheet__c = weekelyTimeEntries.Id;
        dayEntries.SVMXC__Timsheet_Day__c =  System.Today();
        insert dayEntries;
        
        //insert work detail
        SVMXC__Service_Order_Line__c woDetail = new SVMXC__Service_Order_Line__c();
        Id workDetailRecordTypeId = Schema.SObjectType.SVMXC__Service_Order_Line__c.getRecordTypeInfosByName().get('Usage/Consumption').getRecordTypeId();
        woDetail.RecordTypeId = workDetailRecordTypeId;
        woDetail.SVMXC__Service_Order__c = workOrder.Id;
        woDetail.SVMXC__Line_Type__c ='Labor';
        woDetail.SVMXC__Line_Status__c = 'Processed';
        woDetail.SVMXC__Start_Date_and_Time__c = system.today();
        woDetail.SVMXC__End_Date_and_Time__c = system.today()+1;
        woDetail.SVMXC__Group_Member__c =  tech.Id;
        insert woDetail; 

        
        scheduledBatchTimeEntryForWorkDetail scheWlClass = new scheduledBatchTimeEntryForWorkDetail();
        
         String sch ='0 48 * * * ?'; 
         System.schedule('Schedule to send email admin test', sch,scheWlClass);
        
        Integer intBatchSize = 100;
        Database.executebatch(scheWlClass, intBatchSize);

    }

}