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
aressaress 

Test class for Batch apex that run every midnight

Need Test class for following Batch apex that check closed won opportunity and send mail every midnight.
Please add positive negative and bulk test cases with 100% code coverage.

global class ContactWithClosedWonOpportunities 
  implements Database.Batchable<sObject>, Database.Stateful {
  
  /**
    This Map will store the contact email IDs and respective List of Opportunites.
   */
  Map<String,List<Opportunity>> contactOpprtunitiesMap = 
    new Map<String,List<Opportunity>>();
  
  /**
    This method will Query all Contacts associate with Account having Closed Won Opportunities.
    @return Database.QueryLocator
   */
  global Database.QueryLocator start(Database.BatchableContext BC) {
    return Database.getQueryLocator(
      'SELECT ' +
        'Name, ' +
        '( SELECT Email FROM Contacts WHERE Preferred_Contact__c = TRUE LIMIT 1 ), ' +
        '( SELECT Name, Amount FROM Opportunities WHERE StageName LIKE \'Closed Won\') ' +
      'FROM ' +
        'Account ' +
      'WHERE ' +
        'id ' +
      'IN ' +
        '(SELECT AccountId FROM Contact WHERE Preferred_Contact__c = TRUE)'
    );
  }

  /**
    This method will add the values in contactOpportunitesMap.
    @return Nothing.
   */
     global void execute(Database.BatchableContext BC, List<sObject> scope) {
    List<Account> accountList = (List<Account>) scope;
    System.debug(scope + '-------------------------  ');
    for(Account accountRecord : accountList) {
      if(accountRecord.Contacts[0].email != null) {
        contactOpprtunitiesMap.put(
          accountRecord.Contacts[0].email, 
          accountRecord.Opportunities
        );
      }
    }
  }
  
  /**
    This method will send to each primary contact with Opportunity name and Amount.
    @return Nothing.
   */
  global void finish(Database.BatchableContext BC) {
    List<Messaging.SingleEmailMessage> mails = new List<Messaging.SingleEmailMessage>();
    for( String mailId : contactOpprtunitiesMap.keySet() ) {
      Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

      List<String> sendTo = new List<String>();
          sendTo.add(mailId);
          mail.setToAddresses(sendTo);

      mail.setReplyTo('ayisha@gmail.com');
      mail.setSubject('All Closed Won Opportunities');

      String body = '<html><body>Dear Sir/Mam, <br/><br/>'; 
      body += 'All Closed Won Opportunities are - <br/>';
      Decimal total = 0;
      for( Opportunity opportunityRecord : contactOpprtunitiesMap.get(mailId) ) {
        body += '&nbsp;&nbsp;&nbsp;&nbsp;' + opportunityRecord.Name + ':  ' + 
            opportunityRecord.Amount + '<br/>';
        total += opportunityRecord.Amount;
      }
      body += '<br/>&nbsp;&nbsp;&nbsp;&nbsp; <b>Total: ' + total + '</b></body></html>';
      mail.setHtmlBody(body);
      System.debug(body);
      mails.add(mail);
    }
    Messaging.sendEmail(mails);
  }
  
}
Naveen IlaNaveen Ila
Follow below steps: 

1) Create a record on  that meets the criteria in the Start method SOQL (At leaving all set of data)
2) Invoke the batch class in Test class method (Use Test.startTest()  and Test.stopTest() )
Test.startTest();

    Database.excute(batchSize, new ContactWithClosedWonOpportunities ());

Test.stopTest();

The above code runs the batch class Syncronusly in Test class context.