Use Case:
Chaining of Queueable Jobs
When a new Lead is inserted,
- Create an account with Name, Industry and BillingAddress same as Lead’s Company, Industry and Address.
- Create a Contact with FirstName, LastName, Account same as Lead’s FirstName, LastName and Account’s Name respectively.
trigger LeadTrigger on Lead (after insert) {if(Trigger.isAfter) {if(Trigger.isInsert) {// Call a Queueable apex which would create an account using company's nameQueueableAccount queueableAcc = new QueueableAccount(Trigger.new);System.enqueueJob(queueableAcc);}}}public class QueueableAccount implements Queueable {@TestVisible private static Boolean queueableAccountRun = true;List<Lead> leadsList = new List<Lead>();// Constructor to get list of new Leads insertedpublic QueueableAccount(List<Lead> leadsList) {this.leadsList = leadsList;}public void execute(System.QueueableContext qc) {Map<Lead,Account> leadsWithAccounts = new Map<Lead,Account>();// Add account for each Lead in the list "accountsList" and insert listfor(Lead lead : leadsList) {Account newAcc = new Account(Name = lead.Company,Industry = lead.Industry,BillingStreet = lead.Street,BillingCity = lead.City,BillingState = lead.State,BillingCountry = lead.Country,BillingPostalCode = lead.PostalCode);leadsWithAccounts.put(lead, newAcc);}insert leadsWithAccounts.values();// Call QueueableContact to create Contacts from Leads.if(queueableAccountRun) {QueueableContact queueableCon = new QueueableContact(leadsWithAccounts);System.enqueueJob(queueableCon);}}}public class QueueableContact implements Queueable {Map<Lead,Account> leadsWithAccounts = new Map<Lead,Account>();public QueueableContact(Map<Lead,Account> leadsWithAccounts) {this.leadsWithAccounts = leadsWithAccounts;}public void execute(QueueableContext qc) {// Create an empty list of contactsList<Contact> contactsList = new List<Contact>();// Iterate through each key of Map leadsWithAccountsfor(Lead lead : leadsWithAccounts.keySet()) {// Get the values from the each Lead and add it into the contactsListcontactsList.add(new Contact(FirstName = lead.FirstName,LastName = lead.LastName,AccountId = leadsWithAccounts.get(lead).Id));}insert contactsList;}}
Test Class:
Note: We can’t chain queueable jobs in an Apex test. Doing so results in an error. So in order to test the functionality, we will write test method for each of the Account and Contact Queueable class.
Test QueueableAccount class – Insert a new Lead. After insertion a new Lead, an Account should be created with Lead’s company name. To avoid running QueueableContact class so that we don’t get the error, we can use @TestVisible boolean value which can control the execution of the class.
Test QueueableContact class – Insert a new Lead and an Account and call QueueableContact class, Contact should be created using the details from Lead and Account.
@isTestprivate class LeadTriggerTest {// This method will only test QueueableAccount class because in chaining only 1 class can be tested at a time to avoid Maximum stack depth error// After insertion a new Lead, an Account should be created with Lead's company name.@isTeststatic void testQueueableAccount() {// Insert new lead// and set QueueableAccount.queueableAccountRun to false, so that the Contact Queueable class won't be called// and "Maximum stack depth has been reached." error can be ignoredLead newLead = new Lead(FirstName = 'Bob',LastName = 'Marley',Company = 'Peace Ltd',Industry = 'Entertainment');Test.startTest();QueueableAccount.queueableAccountRun = false;insert newLead;Test.stopTest();// Assert that account should be created with same name as Lead's company nameAccount acc = [Select Id, Name From Account LIMIT 1];System.assertEquals(newLead.Company, acc.Name, 'Account created does not have the name same as Lead Company name.');}// This method will test QueueableContact class.// Insert a new Lead and an Account and call QueueableContact class// Assert the Contact's FirstName, LastName and AccountId@isTeststatic void queueableContactTest() {// Create a LeadLead newLead = new Lead(FirstName = 'Bob',LastName = 'Marley',Company = 'Peace Ltd',Industry = 'Entertainment');QueueableAccount.queueableAccountRun = false;insert newLead;// Create an accountAccount acc = new Account(Name = 'Peace Ltd',Industry = 'Entertainment');insert acc;Map<Lead,Account> leadsWithAccounts = new Map<Lead,Account>();leadsWithAccounts.put(newLead, acc);// Call QueueableContact class and assert the first name, last name and account idTest.startTest();QueueableContact queueable = new QueueableContact(leadsWithAccounts);System.enqueueJob(queueable);Test.stopTest();Contact con = [Select Id, FirstName, LastName, AccountId From Contact LIMIT 1];System.assertEquals(newLead.FirstName, con.FirstName, 'Contact First Name does not match with Lead First Name.');System.assertEquals(newLead.LastName, con.LastName, 'Contact Last Name does not match with Lead First Name.');System.assertEquals(acc.Id, con.AccountId, 'Contact Account Id does not match with Account created from Lead');}}
Code Coverage:
LeadTrigger - 100%
QueueableAccount - 89%
QueueableContact - 100%