[SalesForce] Test Coverage for Batch Class

I have the following Batch class which operates on a custom object (Sample__c) and the default Contact object. My test class goal was to create a list of Samples which I know satisfy the batch's query , insert those and then run the batch with an assert on all the created Samples which tests what the batch should have modified. Right now my test is failing and I'm getting 0% coverage on the batch class. Any help would be appreciated, thank you.

global class SampleSurveyEmailHandler implements Database.Batchable<sObject>{

NPS_Survey_Date_Window__c window = NPS_Survey_Date_Window__c.getInstance();
Date minimum = Date.today().addDays(window.Minimum__c.intValue());
Date maximum = Date.today().addDays(window.Maximum__c.intValue());
Set<String> productCodes = new Set<String>{'WISDOMUK_IN', 'WISDOM_IN', 'Wisdom_PB', 'Wisdom_DD'};
List<String> emailsNotUsed = new List<String>{'bev@mirandalambert.com', 'annbelles@aol.com', 'feragen.at'
    ,'dna-worldwide.co.uk', 'vetgen.com', 'blackdogdna.com', 'canix-dna.com', 'dna-worldwide', 'mss.effem.com',
    'anidom.de', 'whatbreedismydog', 'info@canix-dna.com', 'customercare@marsveterinary.com', 'wisdom@wisdompanel.com',
    'info@anidom.de', 'info@blackdogdna.com', '4dogs@caninelifetimehealth.org', 'program@searchdogfoundation.org'};
Integer sixMonths = 180;
Integer surveySentDifference =0;
public String query = 'SELECT Id,Product_Code__c,Consumer_Email__c, Consumer__r.NPS_Email_Sent_On__c FROM Sample__c WHERE'+
    ' Survey_Mail_Sent__c = false AND' +
    ' RGS_Report_Regenerated_On__c = NULL AND'+
    ' Financial_State__c = NULL AND'+
    ' Has_Escalated_Case__c = false AND'+
    ' RGS_Report_Ready_On__c >:' + maximum +
    ' AND RGS_Report_Ready_On__c <:' + minimum;

//retrieved from custom setting so we can stop the process and re-run with
//other settings if need be


public SampleSurveyEmailHandler(){
}

global Database.QueryLocator start(Database.BatchableContext BC)
{


    return Database.getQueryLocator(query);
}

global void execute(Database.BatchableContext BC, List<Sample__c> scope)
{
    // we really just need the Id from this object so we can send the correct template for every environment
    EmailTemplate template = [SELECT Id, Name FROM EmailTemplate WHERE Name = 'NPS_Customer_Survey'];
    // We'd like to send a customer another survey if they purchase samples more than 180 days apart
     for(Sample__c sample : scope){
        boolean validEmail = true;
        for( String key : emailsNotUsed){
            if(sample.Consumer_Email__c.contains(key)){
                validEmail = false;
                break;
            }
        }
        if(sample.Consumer__r.NPS_Email_Sent_On__c == NULL){
            //this consumer hasn't received a Survey Email so we want to force one through
            surveySentDifference = 181;
            }
        else{
            surveySentDifference = date.valueof(sample.RGS_Report_Ready_On__c).daysBetween(sample.Consumer__r.NPS_Email_Sent_On__c);
        }

        if(productCodes.contains(sample.Product_Code__c) && validEmail == true && surveySentDifference > sixMonths){
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            mail.setTargetObjectId(sample.Consumer__r.Id);
            mail.setTemplateId(template.Id);
            Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
            sample.Survey_Mail_Sent__c = true;
            sample.Consumer__r.Survey_Email_Sent__c = true;
            sample.Consumer__r.NPS_Email_Sent_On__c = Date.today();
            }

     }
     update scope;
}
global void finish(Database.BatchableContext BC){}

}

    @isTest
private class TestClass_SampleSurveyEmailHandler {

  static testMethod void unitTest(){
    List<Sample__c> samples = MSS_TestData.createSampleRecords(20);
    Date twoWeeksAgo = Date.today().addDays(-15);
    Contact cont = new Contact();
    cont.Email = 'sam.vanryssegem@mss.effem.com';
    List<Id> sampleIds = new List<Id>{};
    for(Sample__c sample : samples){
      sample.RGS_Report_Ready_On__c = twoWeeksAgo;
      sample.Consumer__r = cont;
      sample.Product_Code__c = 'WISDOM_IN';
      sampleIds.add(sample.Id);

    }
  String query = 'SELECT Id,Product_Code__c,Consumer_Email__c, Consumer__r.NPS_Email_Sent_On__c FROM Sample__c WHERE'+
        ' Id IN ' + sampleIds;
    insert samples;

    Test.startTest();
    List<Sample__c> queriedSamples = [SELECT Id,Product_Code__c,Consumer_Email__c, Consumer__r.NPS_Email_Sent_On__c FROM Sample__c WHERE Id IN :sampleIds];
    System.assert(queriedSamples.size() >0);
    SampleSurveyEmailHandler handler = new SampleSurveyEmailHandler();
    handler.query = query;
    Database.executeBatch(handler);
    for(Sample__c sample : samples){
      System.assert(sample.Consumer__r.NPS_Email_Sent_On__c != NULL);
    }
    Test.stopTest();

  }
}

Best Answer

One problem is that the query you are using in your test case is just appending the list of IDs to the query string which will not include the necessary braces or quotes.

Instead you need something like this:

String inTerm = '(\'' + String.join(sampleIds, '\',\'') + '\')';

and append that to your two query strings.

Invalid SOQL syntax would stop your batchable code ever being reached.

Your test will need to requery the Sample__c object after the Test.stopTest() call to meaningfully assert the NPS_Email_Sent_On__c value.

(I also suggest it would be better to not change the query used in the batchable in the test but rather to create objects in the test case that result in matches from the query.)

Related Topic