2

I am getting a strange error when running my test method:

@isTest
public class Batch_Ent_Update_Eqn_Status_TESTMETHOD{

public static testmethod void testBatch_Ent_Update_Eqn_Status(){
    //List<cif_entity__c> lstEntities = [Select Name, ID_CIF__c, CIF_id__c, Equation_Status__c from cif_entity__c where equation_status__c = :'Updating Equation']; 
    //system.debug('number before = ' + lstEntities.size());
    //System.assertEquals(1, lstEntities_Before.size(),'BEFORE = ' +  lstEntities_Before.size());  

    test.startTest();
    BATCH_Ent_Update_Eqn_Status myClass = new BATCH_Ent_Update_Eqn_Status();
    myClass.lnumber = 'No Limit';
    database.executebatch(myClass,1);

    test.stopTest();
    }
}

The test fails every time with a message System.NullPointerException: Attempt to de-reference a null object and the stacktrace given is:

Class.BATCH_Ent_Update_Eqn_Status.start: line 13, column 1

But I know that the code has run because I have received an email with the results in a csv file.

Here is the batch class I am testing which sends the email:

global class BATCH_Ent_Update_Eqn_Status implements Database.Batchable<SObject>, Database.Stateful {
private integer RecordNo = 0;
public string scope = '1';
public String lnumber = 'No Limit';
public string updatedEntities = '';
public string csvData = '';

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

    system.debug('start');

    Bulk_Address_Switch__c bas = Bulk_Address_Switch__c.getInstance('isBulkUpdate');
    bas.Field_Value__c = 'Yes';
    update bas;

    RecordNo = 0;

    system.debug('set qry');//Updating Equation
    string query = 
        'Select Name, ID_CIF__c, CIF_id__c, Equation_Status__c from cif_entity__c where equation_status__c =\'Updating Equation\'';

    if(lnumber != 'No Limit')query += ' limit '+lnumber;

    system.debug('return QUERY STRING:');
    return Database.getQueryLocator(query);
}

global void execute(Database.BatchableContext context, List<cif_entity__c> scope) {

    system.debug('in execute');

    updatedEntities='';

    Datetime myDatetime = Datetime.now();
    String myDatetimeStr = myDatetime.format('dd/MM/yyyy');
    system.debug('date = ' + myDatetimeStr);   

    system.debug('start loop through scope');   

    for(cif_entity__c c:scope){
        system.debug('in loop through query, #' + RecordNo);
        updatedEntities += string.valueOf(c.Name)+',' +  string.valueOf(c.ID_CIF__c)+',' + myDatetimeStr + ',' +c.Equation_Status__c +',';
        c.Equation_Status__c = 'Equation Updated'; //
        updatedEntities += c.Equation_Status__c + '\n';
        system.debug('Entity record for: ' + c.Name);
        RecordNo++;
        update scope;
        csvData +=updatedEntities;
        system.debug('Update records record no: ' + RecordNo);
    }       
    system.debug( RecordNo + ' records updated!');
    system.debug(csvData);

}

/**
 * @description gets invoked when the batch job finishes. Place any clean up code in this method.
 * @param context contains the job ID
 */ 
global void finish(Database.BatchableContext context) {
    //Set Is bulkUpdate to No
    system.debug('set Bulk_Address_Switch to No');
    Bulk_Address_Switch__c bas = Bulk_Address_Switch__c.getInstance('isBulkUpdate');
    bas.Field_Value__c = 'No';
    update bas;

    string csvHeader='Name, Cif ID, Last Modified Date, old Equation Status, new Equation Status\n';
    csvData = csvHeader + csvData;

    Messaging.EmailFileAttachment csvAttc = new Messaging.EmailFileAttachment();

    //Create csv attachment     
    blob csvBlob = Blob.valueOf(csvData); //updatedEntities
    string csvname= 'UpdatedEntityrecords.csv';
    csvAttc.setFileName(csvname);
    csvAttc.setBody(csvBlob);

    //Create Email      
    Messaging.SingleEmailMessage email =new Messaging.SingleEmailMessage();
    String[] toAddresses = new list<string> {'[email protected]'}; 
    String[] ccAddresses = new list<string> {'[email protected]'};

    email.setSenderDisplayName('Entity records Equation status Batch job');
    email.setSubject('Entity records Equation status updated');       

    email.setToAddresses( toAddresses );
    email.setCcAddresses( ccAddresses );

    email.setPlainTextBody('Please see the attached file');
    email.setFileAttachments(new Messaging.EmailFileAttachment[]{csvAttc});

    Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});
    }
}

it essentially finds all the records in our custom object that have a certain status set in a field, and updates them...

So what am I doing wrong in my test method, I cannot even begin to look for code overage until it even works...

5
  • 2
    Are you creating any data in your test?
    – Girbot
    Commented Mar 18, 2016 at 17:09
  • @Girbot: well, no - there is already data in there, so I am just running the batch to do the update... then calling System.assetEquals to check the results...do I need to create a basic record as part of my test, then call the method on that? Commented Mar 18, 2016 at 17:11
  • 1
    Yes you need to create the data you need in a test method/class. I didn't even look at the batch class because I couldn't see any data setup in the test method.
    – Girbot
    Commented Mar 18, 2016 at 17:13
  • @Girbot: thanks, should I put the code to create the record after the test.startTest() or before? Commented Mar 18, 2016 at 17:14
  • 1
    Before then your SOQL query limit will be refreshed by using test.startTest()
    – Girbot
    Commented Mar 18, 2016 at 17:16

1 Answer 1

5

This is a bit of bare bones answer which I will add more detail to when I can, but it doesn't look like you are creating any data in your test class.

Create all the data you need before calling test.startTest() - including any custom setting records you need. I can see one in there:

Bulk_Address_Switch__c setting = new Bulk_Address_Switch__c(Name='isBulkUpdate')
upsert setting;

With regards to test.startTest(), from the Dev Docs:

Each test method is allowed to call this method only once. All of the code before this method should be used to initialize variables, populate data structures, and so on, allowing you to set up everything you need to run your test. Any code that executes after the call to startTest and before stopTest is assigned a new set of governor limits.

2
  • 3
    Hey @Girbot, nice answer. It seemed like there were a couple missing words I added in, and just fleshed out the custom setting detail a bit. Hope you don't mind, seemed better than adding an answer just to get that detail in there. +1, and awesome avatar.
    – Adrian Larson
    Commented Mar 19, 2016 at 0:04
  • 1
    @AdrianLarson Not at all, I appreciate it. It was my intention to come back to it as I added it in a rush :)
    – Girbot
    Commented Mar 19, 2016 at 9:25

You must log in to answer this question.

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