As we Know, We can have only 1 Test.startTest() and Test.stopTest() per method,
Each test method is allowed to call this method only once, reference Official Documentation
If you have a schedulabe class calling a future method, or any other asychronous process chained in this way. They cant be tested.
Due to the following reasons:
- Salesforce's handling of asynchronous operations can make testing a future method from a schedulable class challenging.
- Asynchronous execution can cause issues as the future method may not complete before the test asserts results.
- Salesforce's Test.startTest() and Test.stopTest() control asynchronous code execution, but calling a future method from within a schedulable class complicates the execution flow.
- Test methods not waiting for asynchronous calls can also cause issues.
- Salesforce enforces strict limits on asynchronous operations within a test context, and the platform's isolation of test data may prevent future methods from accessing or modifying expected data, leading to test assertion failures.
Example
Schedulabe class:
public class ScheduledFuture implements Schedulable {
public void execute(SchedulableContext context) {
// For example, we schedule the future method to process a list of Account records
List<Account> accounts = [SELECT Id FROM Account LIMIT 10]; // Fetch some sample records
List<Id> accountIds = new List<Id>();
for (Account acc : accounts) {
accountIds.add(acc.Id);
}
// Call the future method
FutureMethods.processRecords(accountIds);
}
}
Future:
public class FutureMethods {
@future
public static void processRecords(List<Id> recordIds) {
// Simulate a long-running operation
for (Id recordId : recordIds) {
// For example, update some records or perform an action
Account acc = [SELECT Id, Name FROM Account WHERE Id = :recordId LIMIT 1];
acc.Name = 'Updated Name ' + System.currentTimeMillis();
update acc;
}
}
}
Test code:
@isTest
private class ScheduledFutureTest {
@isTest
static void testScheduledFuture() {
// Insert some sample accounts to test with
List<Account> accounts = new List<Account>();
for (Integer i = 0; i < 5; i++) {
accounts.add(new Account(Name = 'Test Account ' + i));
}
insert accounts;
// Create the cron expression for scheduling
String cronExp = '0 0 0 * * ?'; // Every day at midnight
// Schedule the job
Test.startTest();
System.schedule('Test ScheduledFutureJob', cronExp, new ScheduledFuture());
Test.stopTest();
// Verify that the future method was called and processed the records
// Check the AsyncApexJob object for the status of the future method
List<AsyncApexJob> jobs = [SELECT Status, JobType FROM AsyncApexJob WHERE JobType = 'Future'];
System.assertEquals(1, jobs.size(), 'Future method should have been executed');
System.assertEquals('Completed', jobs[0].Status, 'The future method should have been completed');
// Optionally, check if records were updated
List<Account> updatedAccounts = [SELECT Name FROM Account WHERE Id IN :accounts];
for (Account acc : updatedAccounts) {
System.assert(acc.Name.startsWith('Updated Name'), 'Account name should have been updated');
}
}
}
References:
https://salesforce.stackexchange.com/questions/61239/testing-scheduled-apex-containing-future-method
https://salesforce.stackexchange.com/questions/244791/how-do-i-test-asynchronous-apex
https://salesforce.stackexchange.com/questions/311695/unit-testing-schedulable-that-calls-future-method
Comments
Post a Comment