[SalesForce] Test execution order issues with Queueable and @future method

Test code:

* Test.startTest();
* System.enqueueJob(new MyJob());
* Test.stopTest();
* System.debug('Quering record for assertion');

Expected Queueable job execution:

* Job Start
* Query records
* Callout
* --------------> @future method
* DML1            *
* Job End         * Callout
                  * DML2

When quering record after Test.stopTest() changes of DML1 are visible only, but not of DML2.

Actual debug log order:

14:49:52.9 -> DML1
14:49:52.9 -> Quering record for assertion
14:49:52.237 -> DML2

Expected log order:

1. DML1
2. DML2
3. Quering record for assertion

Problem: after Test.stopTest() I query records and want to assert changes of DML1 and DML2 together, but record is only at DML1 state.

Best Answer

What you describe is an inherent limitation of testing code that runs asynchronously in a future context. When you enqueue your Queueable class to run, you're scheduling it to run at "some time in the future" when resources become available. As per the documentation, the code in your queueable class will execute when Test.StopTest() is encountered in your test method.

The problem you're facing is that your asynchronous queueable class calls an asynchronous method via an @future call from within it. The only way that code would execute is if you could do another Test.StopTest(), however, it's clear that you can't start and stop your test again for that to occur.

Clearly, you can test the asynchronous method on it's own, but the issue for you is, what can you possibly do to assert that that the method was at least called in your code? Since you can test it separately, what you want to know more than anything is that the method was called. To do that, you can utilize the limits class.

You should be able to use getLimitFutureCalls() and getFutureCalls() both before Test.StopTest() and after Test.StopTest() to be able to assert that the future call was made when your queueable class executed.