Creating a test class for a chaining queueable job in Apex involves understanding how queueable jobs work, how to chain jobs, and how to use the AsyncOptions
class to control the behaviour of the jobs. With these tools, you can create robust and reliable asynchronous processes in your Salesforce applications.
In our AccountProcessingQueueable
class, we chain jobs by enqueuing a new job within the execute
method if there are more accounts to process.
public class AccountProcessingQueueable implements Queueable {
private Set<Id> accountIds;
private Integer batchSize;
public AccountProcessingQueueable(Set<Id> accountIds, Integer batchSize) {
this.accountIds = accountIds;
this.batchSize = batchSize;
}
public void execute(QueueableContext context) {
List<Account> accountsToProcess = [
SELECT Id, Name, AnnualRevenue
FROM Account
WHERE Id IN :accountIds
LIMIT :batchSize
];
System.debug(accountsToProcess.size());
// Perform complex calculations and updates here
for (Account account : accountsToProcess) {
account.Description = 'Updated by AccountProcessingQueueable';
}
update accountsToProcess;
// If there are more accounts to process, enqueue the next job in the chain
if (accountIds.size() > batchSize) {
for (Account account : accountsToProcess) {
accountIds.remove(account.Id);
}
System.enqueueJob(new AccountProcessingQueueable(new Set<Id>(accountIds), batchSize));
}
}
}
Creating a Test Class
When creating a test class for a queueable job, we need to create test data, enqueue the job, and then verify the results. The Test.startTest() and Test.stopTest() methods are used to denote the start and end of the test. Between these two methods, we enqueue our job.
@IsTest
public with sharing class AccountProcessingQueueableTest {
@IsTest
public static void testQueueable() {
List<Account> accounts = new List<Account>();
for (Integer i = 1; i <= 7; i++) {
accounts.add(new Account(Name = 'Test ' + i));
}
insert accounts;
AsyncOptions asyncOptions = new AsyncOptions();
asyncOptions.maximumQueueableStackDepth = 4;
Test.startTest();
Set<Id> accountIds = (new Map<Id, SObject>(accounts)).keySet();
System.enqueueJob(new AccountProcessingQueueable(accountIds, 2), asyncOptions);
Test.stopTest();
List<Account> updatedAccounts = [SELECT Id, Description FROM Account WHERE Id IN :accounts];
for (Account account : updatedAccounts) {
System.assertEquals('Updated by AccountProcessingQueueable', account.Description);
}
}
}
The Rationale Behind the Test Data
In the AccountProcessingQueueableTest
class, we create 7 account records. This number is chosen to demonstrate the functionality of the queueable job and its chaining mechanism. The AccountProcessingQueueable
job processes accounts in batches, with a batch size of 2. With 7 accounts, we ensure that the job will need to be chained multiple times to process all accounts.
List<Account> accounts = new List<Account>();
for (Integer i = 1; i <= 7; i++) {
accounts.add(new Account(Name = 'Test ' + i));
}
insert accounts;
Understanding MaximumQueueableStackDepth
The maximumQueueableStackDepth
property of the AsyncOptions
class is used to limit the depth of the queueable job stack. In this case, it is set to 4. This means that the maximum number of chained jobs that can be added to the stack is 3. If the limit is reached, any further attempt to add a job to the stack will result in a System.AsyncException
.
AsyncOptions asyncOptions = new AsyncOptions();
asyncOptions.maximumQueueableStackDepth = 4;
Running the Queueable Job
The queueable job is run 4 times before it exits. This is because the batch size is set to 2, and we have 7 accounts to process. The job processes 2 accounts at a time, so it needs to run 4 times to process all 7 accounts. The last run will only process 1 account, as there are no more accounts left to process.
Test.startTest();
Set<Id> accountIds = (new Map<Id, SObject>(accounts)).keySet();
System.enqueueJob(new AccountProcessingQueueable(accountIds, 2), asyncOptions);
Test.stopTest();
0 comments:
Post a Comment