1

To chain a execution of a batchable object, I pass the batchable contructor a ICommand.

public interface ICommand {
    void Execute();
}

When testing this approach I create a test ICommand which just flags when it has been executed.

private class TestCommand implements ICommand
{
    public boolean HasExecuted
    {
        get;
        private set;
    }

    public TestCommand()
    {
        HasExecuted = false;
    }

    public void Execute()
    {
        HasExecuted = true;
    }
}

The strange thing is that according to the execution log the Execute method is called as expected and HasExecuted is assigned a value of true, but after Test.stopTest(); is invoked the value of HasExecuted is assigned back to false by some strange (impossible) method.

14:57:16:042 VARIABLE_ASSIGNMENT [56]|this.HasExecuted|true|0x56461b13
...
14:57:16:053 METHOD_EXIT [48]|System.Test.stopTest()
14:57:16:053 VARIABLE_ASSIGNMENT [EXTERNAL]|this|{"HasExecuted":false}|0x43c87c0c
**14:57:16:053 EXCEPTION_THROWN [51]|System.AssertException: Assertion Failed: Expected: true, Actual: false**

Is this normal behaviour for for apex to prevent changing changing object values by reference over async execution contexts, or is something else happening?

1 Answer 1

1

The reference isn't valid in asynchronous execution. Specifically, when you call System.schedule, System.enqueueJob, or Database.executeBatch, the class is serialized and put in to a queue. This effectively makes a copy of the object, not the original. A more particular example might be useful:

public class Example implements Queueable {
  public String value;
  public void execute(QueueableContext context) {
    System.debug(value);
  }
}
...
Example e = new Example();
e.value = 'Hello';
System.enqueueJob(e);
e.value = 'World';
// output will be "Hello"
Test.stopTest();
// output will be "World"
System.debug(e.value);

Since the copy is what actually runs, the original doesn't get modified.

The typical scenario, if you want to use this model for unit tests, is to set a private static test visible variable:

@TestVisible static Boolean hasExecuted = false;
...
public void execute(QueueableContext context) {
  hasExecuted = true;
}
...
  System.enqueueJob(q);
  Test.stopTest();
  System.assert(Example.hasExecuted,'Expected execution of queueable class');

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.