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
AntonPavlovAntonPavlov 

need help to fix apex batch test

Apex code 
this code not cover for 100%
global class closeAllDealsMonthAgo implements 
   Database.Batchable<SObject>, Database.Stateful{ 

   List<Opportunity> listRecords = new List<Opportunity>();
   global Database.QueryLocator start(Database.BatchableContext BC){
         String query = 'Select Id, Name, CloseDate,createdDate,StageName From Opportunity WHERE CloseDate=THIS_MONTH';
         return Database.getQueryLocator(query);
   }
   global void execute(Database.BatchableContext BC, List<SObject> scope){
      for(Opportunity obj : (Opportunity[]) scope){  
         if(Date.Today()>obj.CloseDate && (obj.StageName != 'Closed Won' || obj.StageName !='Closed Lost')){
            obj.StageName = 'Closed Lost';
            listRecords.add(obj);
         }
         if(Date.Today()>obj.createdDate.addMonths(1) && (obj.StageName != 'Closed Won' || obj.StageName !='Closed Lost')){
            obj.StageName = 'Closed Lost';
            obj.CloseDate= Date.today();
            listRecords.add(obj);
         }
      }
   }
   global void finish(Database.BatchableContext BC){
      if(!listRecords.isEmpty()){
         update listRecords;
      }
   }      
}
test code 
@isTest             
private class closeAllDealsMonthAgoTest {
    static testmethod void testbatch() {
        Integer count = 200;
        Account acc = new Account(Name='Test Account');
        insert acc;
        
        List<Opportunity> opps = new List<Opportunity>();
        for (integer i=0; i<count; i++){
            Opportunity opp = new Opportunity();
            opp.AccountId=acc.Id;
            opp.Name='My Opportunity '+i;
            opp.StageName='Qualification';
            opp.CloseDate= Date.today().addDays(-5);
            opps.add(opp);
        }
        insert opps;
        System.assertEquals(count, opps.size());
       
       Test.startTest();
           closeAllDealsMonthAgo obj = new  closeAllDealsMonthAgo();
           Database.executeBatch(obj);
       Test.stopTest();
      
         List<Opportunity> oppUpdatedList = [SELECT Id,StageName,CloseDate FROM Opportunity];
        for(Opportunity o : oppUpdatedList){
            if(Date.Today()>o.CloseDate && (o.StageName != 'Closed Won' || o.StageName !='Closed Lost')){
                o.StageName = 'Closed Lost';
                System.assertEquals('Closed Lost', o.StageName);    
            }
        }
    }
}
Andrew GAndrew G
3 options:
  1. Use Test.setCreateDate
  2. Use Test.loadData()
  3. Use JSON.deserialize()
for Test.setCreateDate - something like:
//after insert of opps, loop to set the created date

insert opps;

for (Opportunity opp : opps ) {
  Test.setCreateDate(opp.Id, Datetime.now().addDays(-33));
}

//continue test method

for options 2 or 3, refer to knowledge article:

Set system protected fields for test code coverage (https://help.salesforce.com/articleView?id=000332070&type=1&mode=1)


regards

Andrew
SUCHARITA MONDALSUCHARITA MONDAL

Hi Anton,

Check with the modified code is as below:

Test Class:-------->

 

@isTest             
private class closeAllDealsMonthAgoTest {
    static testmethod void testbatch() {
        Integer count = 200;
        Account acc = new Account(Name='Test Account');
        insert acc;
        
        List<Opportunity> opps = new List<Opportunity>();
        for (integer i=0; i<count; i++){
            Opportunity opp = new Opportunity();
            opp.AccountId=acc.Id;
            opp.Name='My Opportunity '+i;
            opp.StageName='Qualification';
            opp.CloseDate= Date.today() - 1;  // made changes
            opps.add(opp);
        }
        insert opps;
        System.assertEquals(count, opps.size());
       
       Test.startTest();
           closeAllDealsMonthAgo obj = new  closeAllDealsMonthAgo();
           Database.executeBatch(obj);
       Test.stopTest();
      
         List<Opportunity> oppUpdatedList = [SELECT Id,StageName,CloseDate FROM Opportunity];
        for(Opportunity o : oppUpdatedList){
            if(Date.Today()>o.CloseDate && (o.StageName != 'Closed Won' || o.StageName !='Closed Lost')){
                //o.StageName = 'Closed Lost';  // Your batch class should update the stagename, it shouldn't be explicit
                System.assertEquals('Closed Lost', o.StageName);    
            }
        }
    }
}

 

Note :  Your second "IF Condition", may not cover as we are creating and inserting opportunity on current date i.e. while executing this test class. Therefore createdate.addMonths(1), will not work.

 

Hope this helps!
Thanks
Sucharita
 

Andrew GAndrew G
Hi again

As i re-read the code, even with the suggested change to manipulate the CreateDate you will have an issue.  You are adding to a list which you insert.  From memory, if you insert a List with the same record in the list more than once, an error will be thrown on insert.  You will need to change that List to a Set to avoid the duplication of records in the List.

Otherwise, you would need to create 2 x sets of data and ensure they don't both satisfy the 2 x IF conditions.

regards
Andrew