7

Given the following batch code:

global without sharing class POCBatch implements Database.Stateful, Database.Batchable<Sobject>{

        public static List<String> staticList = new List<String>();
        public List<String> nonStaticList = new List<String>();

        global Database.QueryLocator start(Database.BatchableContext BC) {
            return Database.getQueryLocator([Select Id from Account limit 1]);
        }

        global void execute(Database.BatchableContext BC, List<Sobject> scope) {

            staticList.add('StaticAdd');
            nonStaticList.add('NonStaticAdd');
        }

        global void finish(Database.BatchableContext BC) {
            System.debug('finishStaticList: '+staticList);
            System.debug('finishNonStaticList: '+nonStaticList);
        }
}

and the following test method:

@isTest
private class POCBatchTest {
    @isTest
    static void testPOCBatch(){
        insert new Account(Name = 'For Test');
        POCBatch poc = new POCBatch();
        Test.startTest();
        Database.executeBatch(poc);
        Test.stopTest();
        System.debug('test method static list: '+POCBatch.staticList);
        System.debug('test method non-static list: '+poc.nonStaticList);

    }
}

If you run in a batch versus text context, it gives different results. In both case it is selecting a single Account from the org (but doesn't do anything with it).

Batch context debug output:

finishStaticList: ()

finishNonStaticList: (NonStaticAdd)

Test method debug output:

finishStaticList: (StaticAdd)

finishNonStaticList: (NonStaticAdd)

test method static list: (StaticAdd)

test method non-static list: ()

My questions are:

1) Why are there differences in the finish method output in the different contexts?

2) It appears that the static context is lost in the batch, but the non-static context is lost in the test method. So how can I test the list's contents in the batch's test method?

6

Static variables are wiped out between transactions; since a unit test is a single transaction, the static variable persists during a unit test, but not when ran as live code. The local variable is a bit trickier. You see, when you use Database.executeBatch, it actually serializes the class, which means a copy is created and run later. The version you have "in memory" in the unit test isn't the same object that gets run. This is similar to the reason you need to query records from a database after you perform a DML operation to verify the new values.

For testing purposes, consider doing this:

global without sharing class POCBatch implements Database.Stateful, Database.Batchable<Sobject>{
        public List<String> nonStaticList = new List<String>();
        @TestVisible static POCBatch self;

        global Database.QueryLocator start(Database.BatchableContext BC) {
            self = this;
            return Database.getQueryLocator([Select Id from Account limit 1]);
        }

        global void execute(Database.BatchableContext BC, List<Sobject> scope) {
            nonStaticList.add('NonStaticAdd');
        }

        global void finish(Database.BatchableContext BC) {
            System.debug('finishNonStaticList: '+nonStaticList);
        }
}

From there, you can modify your unit test:

@isTest
private class POCBatchTest {
    @isTest
    static void testPOCBatch(){
        insert new Account(Name = 'For Test');
        POCBatch poc = new POCBatch();
        Test.startTest();
        Database.executeBatch(poc);
        Test.stopTest();
        System.debug('test method non-static list: '+POCBatch.self.nonStaticList);

    }
}
| improve this answer | |
  • That certainly makes sense. But when I tried your code POCBatch.self.nonStaticList still returned empty. – George S. Jun 21 '16 at 20:27
  • 1
    @GeorgeS. This used to work. I'm pretty sure, anyways. I'm going to check some old source code. – sfdcfox Jun 21 '16 at 21:30
0

I was unable to get sfdcfox's solution to work, and eventually just created a (redundant) @TestVisible static list for my unit test. Not pretty, but it does the job.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.