0

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>{'[email protected]', '[email protected]', 'feragen.at'
    ,'dna-worldwide.co.uk', 'vetgen.com', 'blackdogdna.com', 'canix-dna.com', 'dna-worldwide', 'mss.effem.com',
    'anidom.de', 'whatbreedismydog', '[email protected]', '[email protected]', '[email protected]',
    '[email protected]', '[email protected]', '[email protected]', '[email protected]'};
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 = '[email protected]';
    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();

  }
}
1
  • 1
    What is failing?
    – dphil
    Dec 2, 2014 at 20:13

2 Answers 2

1

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.)

0

Try changing your test class code for start and stoptest() location:

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);
Test.startTest();
SampleSurveyEmailHandler handler = new SampleSurveyEmailHandler();
handler.query = query;
Database.executeBatch(handler);
Test.stopTest();
List<Sample__c> lstSamples = [SELECT sample.Consumer__r.NPS_Email_Sent_On__c FROM Sample__c];
for(Sample__c sample : lstSamples){
  System.assert(sample.Consumer__r.NPS_Email_Sent_On__c != NULL);
}
5
  • Can you explain why this might help?
    – Keith C
    Dec 2, 2014 at 20:52
  • The call to Database.executeBatch is included within the Test.startTest and Test.stopTest block. This is necessary for the batch job to run in a test method. The job executes after the call to Test.stopTest. Any asynchronous code included within Test.startTest and Test.stopTest gets executed synchronously after Test.stopTest. Finally, comes verification. More details can be found here Dec 2, 2014 at 20:59
  • The code posted in the question already follow that pattern.
    – Keith C
    Dec 2, 2014 at 21:04
  • Are you sure it follow the pattern? The question code says: --------- ' handler.query = query; Database.executeBatch(handler); for(Sample__c sample : samples){ System.assert(sample.Consumer__r.NPS_Email_Sent_On__c != NULL); } Test.stopTest();' ----- Instead verification should be after Test.stopTest() is called. To verify/validate code need to be updated to query again. Also, query is not in correct format which you already informed. Dec 2, 2014 at 22:08
  • No you are right - I didn't notice that you had moved the Test.stopTest(); too and now with the re-query its better still. Better I think in an answer to explain the changes as well as list them so they stand out and people can learn more.
    – Keith C
    Dec 2, 2014 at 22:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .