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
Bill5Bill5 

Variables not set within a batch job when testing

When setting a instance variables value from within a batch context the value is not retained when testing.

 

Example code:

 

public class FinishLogic {
    public Integer val { get; set; }
}

 

global class UserBatch implements Database.Batchable<sObject>, Database.Stateful {
    
    private final FinishLogic fl;
    
    public UserBatch(FinishLogic fl) {
        this.fl = fl;
    }
    
    global Iterable<sObject> start(Database.BatchableContext bc) {
        return [SELECT Id FROM User LIMIT 1];
    }
    
    global void execute(Database.BatchableContext bc, List<User> scope) {
        //do some stuff
    }
    
    global void finish(Database.BatchableContext bc) {
        fl.val = 5;
    }
}

 

@isTest
public class TestUserBatch {
    
    static testMethod void shouldReturnFive() {
        final FinishLogic fl = new FinishLogic();
        final UserBatch ub = new UserBatch(fl);
        
        Test.StartTest();
        Database.executeBatch(ub);
        Test.StopTest();
        
        System.assertEquals(5, fl.val);
    }
}

 

The test should pass as the value should be 5 but instead returns null. This is a simple example for demonstration purposes, but this behavor is important to test the correct functionality of a batch. 

If I add the line "System.assert(false, 'executing finish);" to the batches finish method the test does correctly fail with the error, therefore the method is being called. Does anybody know why this wouldn't work, or is this a known bug?

 

Thanks

 

crop1645crop1645

Bill:

 

Is the problem the 'final' modifier on FinishLogic?  From the SFDC doc:

 

Final variables can only be assigned a value once, either when you declare a variable or in initialization code. You must
assign a value to it in one of these two places.

 

Bill5Bill5

The FinishLogic var isn't final only the reference to the FinishLogic instance, this is the correct implementation.

 

crop1645crop1645

Bill -- Hmm, I've never done this.

 

* I've used Stateful variables within Batchable classes to pass information between multiiple execute() invocations and the finish() invocation (such as to write a log).

* I've communicated back to the caller of the batch only by updating SObjects in the Database within an execute() method  (this is relevant only for testmethods)

 

Because batch APEX executes in a different context than the method that executes the batch, that SFDC can't pass variables between these two contexts -- In normal (non testmethod) usecases, some method does Database.executeBatch() and immediately gets a return - it doesn't wait around for the batch to finish. So the batch finish() doesn't have a way to tell the caller anything about its 'conclusion'. Thus testmethods have to adhere to this behavior.  

 

See AsyncApexJob for what you can monitor about a batch job -- and it isn't much 

King KooKing Koo
Hi Bill,

I'm having the same problem. Have you resolved your issue?

My issue is documented here, and I believe it is exactly what you're describing:
http://boards.developerforce.com/t5/Apex-Code-Development/Unable-To-access-Variable-values-from-Execute-method-of-batch/m-p/672917#M125086

Thanks
King