@future runs in test without Test.stopTest() – Can that be?

For the last years I expected all async Apex means not to run in tests when there is no Test.stopTest() in my test code.

But now I have a test without this call and a future method is called.

I thought Test.stopTest() is forcing all async Apex to run instantely.

  1. How does it really work, when do I need Test.stopTest()?
  2. Is this also true for Batch?

Answer

It sounds like a bug, or at least it is not documented; I would not depend on this behavior. If you want to test asynchronous code, use Test.stopTest(). This applies for Schedulable, Queueable, Batchable, and @future methods. If you’re not using Test.stopTest(), then you’re obviously not checking the results of the execution, which means you’re only writing code coverage, not quality assurance test methods, which is literally the entire point of unit tests. I’ll check with someone over at salesforce.com and see if something’s changed. In the meantime, you should always use Test.stopTest() and verify the output of any asynchronous code to avoid regression and logic errors when deploying updates to your code. Also, using proper unit testing (by using asserts, for example) will help Salesforce prevent regression bugs when it runs the Apex Hammer Tests each release.


Here’s proof that the methods are indeed executing:

@isTest class q173748 implements Database.Batchable<Integer>, Queueable, Schedulable {
    @isTest static void testFuture() {
        failAsync();
    }
    @isTest static void testBatchable() {
        Database.executeBatch(new q173748());
    }
    @isTest static void testQueueable() {
        System.enqueueJob(new q173748());
    }
    @isTest static void testSchedulable() {
        System.schedule('q173748','0 0 0 * * ?', new q173748());
    }
    // ----------------------------------------------------------- //
    public static void fail() {
        System.assert(false);
    }
    @future static void failAsync() {
        fail();
    }
    // ----------------------------------------------------------- //
    public Integer[] start(Database.BatchableContext context) {
        return new Integer[] { 1 };
    }
    public void execute(Database.BatchableContext context, Integer[] scope) {
        fail();
    }
    public void finish(Database.BatchableContext context) {

    }
    // ----------------------------------------------------------- //
    public void execute(QueueableContext context) {
        fail();
    }
    // ----------------------------------------------------------- //
    public void execute(SchedulableContext context) {
        fail();
    }
}

All of these tests fail, because asynchronous code is indeed called at the end of each unit test method.

Attribution
Source : Link , Question Author : Robert Sösemann , Answer Author : sfdcfox

Leave a Comment