This has been asked here and here, but I'm not satisfied with the answers. Hoping to gain a better understanding of this.
In working through the Apex Specialist Superbadge, the callout portion of the challenge consists of a Schedulable that calls a future. While unit testing this, it became apparent that you can't assert behavior of the future method after scheduling the Schedulable class in a unit test, presumably because Salesforce is waiting only for asynchronous code executed directly from the unit test to complete, and doesn't wait for asynchronous code called from asynchronous code to complete.
Below is a simplified example of what I'm talking about.
public with sharing class ExampleFuture {
public static Boolean doSomethingInvoked = false;
@Future(Callout=true)
public static void doSomething() {
doSomethingInvoked = true;
}
}
public with sharing class ExampleSchedulable implements Schedulable {
public void execute(SchedulableContext context) {
ExampleFuture.doSomething();
}
}
@IsTest
private class ExampleSchedulableTest {
@IsTest
private static void testBehavior() {
Test.startTest();
System.schedule('ExampleSchedulable', '0 0 0 15 3 ? 2022', new ExampleSchedulable());
Test.stopTest();
// This fails
System.assert(ExampleFuture.doSomethingInvoked);
}
}
The assertion in the test class fails, even though Salesforce documentation states
All asynchronous calls made after the startTest method are collected by the system. When stopTest is executed, all asynchronous processes are run synchronously.
Again, I presume they're referring to top-level asynchronous code executed directly from the unit test only, and not anything deeper in the call stack, but it's not obvious.
The weird thing is, executing the unit test with code coverage, and without the assertion, yields 100% coverage in the future method. So it seems the future method is getting called synchronously.
Of course in a real world example I would mock the future call with a spy, but I would love a real explanation of what is happening here.
Any insight is appreciated!