You need to sign in to do that
Don't have an account?
Michael Christie 13
Need to Deactivate Trigger with Low Code Coverage
Hello,
There is an old trigger in our org that needs to be deactivated. However, the trigger's test class only has 65% code coverage. I did not write this code and do not have a background in development. Could anyone offer clear edits to make so that I can successfully deploy the deactivated trigger to production?
Trigger:
Test Class:
Thank you in advance for any assistance you can provide.
There is an old trigger in our org that needs to be deactivated. However, the trigger's test class only has 65% code coverage. I did not write this code and do not have a background in development. Could anyone offer clear edits to make so that I can successfully deploy the deactivated trigger to production?
Trigger:
trigger AccountTrigger on Account (before delete, before insert, before update,after insert) { AccountTriggerHandler.execute(Trigger.new, Trigger.newMap, Trigger.old, Trigger.oldMap, Trigger.isInsert, Trigger.isUpdate, Trigger.isDelete, Trigger.isBefore, Trigger.isAfter); AccountTriggerHandler.executeLeadLink(Trigger.new,Trigger.old,Trigger.isUpdate,Trigger.isBefore,Trigger.isInsert,Trigger.isAfter); }The Class referenced in the trigger:
public with sharing class AccountTriggerHandler { static RecordType applicantRecordType; static Profile adminProfile; static { applicantRecordType = [Select Id From RecordType Where Name = 'Applicants' and sobjecttype = 'Account']; adminProfile = [Select Id, Name From Profile Where Name = 'System Administrator']; } public static void execute(List<Account> newList, Map<Id, Account> newMap, List<Account> oldList, Map<Id, Account> oldMap, Boolean isInsert, Boolean isUpdate, Boolean isDelete, Boolean isBefore, Boolean isAfter) { List<Account> accList = new List<Account>(); if (isDelete) { for (Account acc : oldList) accList.add(acc); } else { for (Account acc : newList) accList.add(acc); } for (Account acc : accList) { if (isBefore) { if (acc.RecordTypeId == applicantRecordType.Id && System.Userinfo.getProfileId() != adminProfile.Id) { acc.addError('Only System Administrators may create, edit, or delete Applicants'); } } } } public static Map<String,Lead> GetLeadsWithAccountEmailAddress(List<Account> accounts){ Map<String,Lead> mappedLeads=new Map<String,Lead>(); Set<String> accountEmails=new Set<String>(); for(Account a:accounts){ accountEmails.add(a.PersonEmail.toLowerCase()); } List<Lead> leads = [Select l.IsConverted, l.Id, l.Email,l.Account__c,l.Application_Status__c From Lead l where l.IsConverted = false and l.Email in:accountEmails]; for(Lead lead:leads){ mappedLeads.put(lead.Email.toLowerCase(),lead); } return mappedLeads; } public static Map<String,Lead> GetLeadsWithAccountExternalReference(List<Account> accounts){ Map<String,Lead> mappedLeads=new Map<String,Lead>(); Set<String> accountExternalRef=new Set<String>(); for(Account a:accounts){ if (!String.isBlank(a.ExternalReference__c)){ accountExternalRef.add(a.ExternalReference__c); } } List<Lead> leads = [Select l.IsConverted, l.Id, l.Email,l.Account__c,l.Application_Status__c From Lead l where l.IsConverted = false and l.Id in:accountExternalRef]; for(Lead lead:leads){ mappedLeads.put(String.valueOf(lead.Id),lead); } return mappedLeads; } public static Map<String,Lead> GetLeadsWithAccountRelation(List<Account> accounts){ Set<Id> leadIds=new Set<Id>(); Map<String,Lead> mappedLeads=new Map<String,Lead>(); for(Account acc:accounts){ leadIds.add(acc.Related_Lead__c); } List<Lead> leads = [Select l.IsConverted, l.Id, l.Email,l.Account__c,l.Application_Status__c From Lead l where l.IsConverted = false and l.Id in:leadIds]; for(Lead lead:leads){ mappedLeads.put(String.valueOf(lead.Id),lead); } return mappedLeads; } public static void CreateLeadLinkAndUpdateLeadData(List<Account> newList,Boolean updateAccount){ Map<String,Lead> mappedLeadsByExternalReference=GetLeadsWithAccountExternalReference(newList); Map<String,Lead> mappedLeads=GetLeadsWithAccountEmailAddress(newList); if (mappedLeads.size()==0 && mappedLeadsByExternalReference.size()==0){ return; } List<Lead> updatedLeads=new List<Lead>(); for(Account acc:newList){ //Check the external ref first Lead lead=mappedLeadsByExternalReference.get(acc.ExternalReference__c); if (lead==null){ lead=mappedLeads.get(acc.PersonEmail.toLowerCase()); } if (lead!=null){ if (updateAccount && lead.Account__c==null){ acc.Related_Lead__c=lead.id; } FieldMapperHelper.AccountToLeadMapping(lead,acc); updatedLeads.add(lead); } } if (updatedLeads.size()>0){ System.debug('Account insert/update updating lead'); update updatedLeads; } } public static void UpdateLeadData(List<Account> accList){ Map<String,Lead> mappedLeads=GetLeadsWithAccountRelation(accList); List<Lead> updatedLeads=new List<Lead>(); for(Account acc:accList){ Lead lead=mappedLeads.get(acc.Related_Lead__c); if (lead!=null){ FieldMapperHelper.AccountToLeadMapping(lead,acc); updatedLeads.add(lead); } } if (updatedLeads.size()>0){ System.debug('Account insert/update updating lead'); update updatedLeads; } } public static void executeLeadLink(List<Account> newList, List<Account> oldList,Boolean isUpdate,Boolean isBefore,Boolean isInsert,Boolean isAfter){ if(isInsert && isBefore){ Map<String,Lead> mappedLeadsByExternalReference=GetLeadsWithAccountExternalReference(newList); Map<String,Lead> mappedLeads=GetLeadsWithAccountEmailAddress(newList); for(Account acc:newList){ Lead lead=mappedLeadsByExternalReference.get(acc.ExternalReference__c); if (lead==null){ lead=mappedLeads.get(acc.PersonEmail.toLowerCase()); } //Check if lead is not null and lead does not have an account already associated with it if (lead!=null && lead.Account__c==null){ acc.Related_Lead__c=lead.Id; } acc.RecordTypeId = FieldMapperHelper.MarkPlusApplicants(acc); } } if (isInsert && isAfter){ CreateLeadLinkAndUpdateLeadData(newList,false); } if (isBefore && isUpdate){ List<Account> accWithNoLeads=new List<Account>(); List<Account> accWithLeads=new List<Account>(); for(Account acc:newList) { acc.RecordTypeId = FieldMapperHelper.MarkPlusApplicants(acc); if (acc.Related_Lead__c==null){ accWithNoLeads.add(acc); } else{ accWithLeads.add(acc); } } //Send the accounts that do not have leads - we need to search if leads exists and then link the lead CreateLeadLinkAndUpdateLeadData(accWithNoLeads,true); //If the account already has a lead, just update the lead no need to relink the accounts UpdateLeadData(accWithLeads); } } }
Test Class:
@isTest private class Test_AccountTriggerHandler { static RecordType applicantRecordType; static { applicantRecordType = [Select Id From RecordType Where Name = 'Applicants' and sobjecttype = 'Account']; } static testMethod void testAccountError() { test.startTest(); Account acc = CreateTestData.createAccount('U_testAccount@tntp.org','externalRef'); acc.FirstName = 'Test Account3'; update acc; delete acc; test.stopTest(); } static testMethod void Account_Gets_Linked_To_Lead_Based_On_Account_ExternalReference_But_With_Different_Emails() { test.startTest(); //Create a lead Lead lead= CreateTestData.createLead('U_test2@tntp.org'); String externalRef=String.valueOf(lead.Id); //Createa a an account with different email address Account acc = CreateTestData.createAccount('U_test1@tntp.org',externalRef); //Get account from database List<Account> accounts = [Select a.PersonEmail,a.Id,a.Related_Lead__c From Account a Where a.PersonEmail ='U_test1@tntp.org']; test.stopTest(); } static testMethod void Account_Gets_Linked_To_Lead_Based_On_Account_Email() { test.startTest(); //Create a lead Lead lead= CreateTestData.createLead('U_test1@tntp.org'); //Createa a an account with same email address Account acc = CreateTestData.createAccount('U_test1@tntp.org','someinvalidId'); //Get Lead from database List<Lead> leads = [Select l.Id,Account__c From Lead l Where l.Email ='U_test1@tntp.org']; //Get account from database List<Account> accounts = [Select a.PersonEmail,a.Id,a.Related_Lead__c From Account a Where a.PersonEmail ='U_test1@tntp.org']; test.stopTest(); } static testMethod void Account_Doesnot_Get_Linked_To_Lead_Because_Of_Missing_Account_ExternalReference() { test.startTest(); //Create a lead Lead lead= CreateTestData.createLead('U_test1@tntp.org'); //Createa a an account with different email address Account acc = CreateTestData.createAccount('U_test2@tntp.org','someinvalidId'); //Get Lead from database List<Lead> leads = [Select l.Id From Lead l Where l.Email ='U_test1@tntp.org']; //Get account from database List<Account> accounts = [Select a.PersonEmail,a.Id,a.Related_Lead__c From Account a Where a.PersonEmail ='U_test2@tntp.org']; //Should find no match System.assertEquals(accounts[0].Related_Lead__c, null); test.stopTest(); } }
Thank you in advance for any assistance you can provide.
In order to deploy to Production, the overall test code coverage needs to be above 75% and none of the Apex test class could fail. We fixed half of the problem by addressing all those exception errors. Now we have to figure out what other code needs additional test code coverage to bring the overall percentage above 75%.
If it is more convenient for you, I can provide you my email and schedule a Zoom meeting to further troubleshoot this together. I know we've been chatting back and forth for awhile so I just wanted to give you this option if you want a quicker fix.
Thanks again for understanding and I look forward to hearing back from you soon!
All Answers
In case you would like to deactivate the trigger you simply need to navigate to the trigger click on edit and then uncheck the active check box then the trigger will be deactivated on doing this.
I hope this helps and in case if this comes useful can you please choose this as best answer so that it can be used by others in the future.
Regards,
Anutej
There is no option to deactivate a trigger in production (by navigating to Setup --> Custom Code --> Apex Triggers). The option exists in sandboxes. However, I am unable to deploy the trigger and its classes from the sandbox to production because code coverage is below 75%. I know there are other methods besides deploying a change set, but simply deactivating a trigger in production is not possible. https://help.salesforce.com/articleView?id=000327373&language=en_US&type=1&mode=1 (https://help.salesforce.com/articleView?id=000327373&language=en_US&type=1&mode=1)
Yes, absolutely. It looks like lines 55 and 34:
Class Name: Test_AccountTriggerHandler
Method Name: Account_Gets_Linked_To_Lead_Based_On_Account_Email
Error Message: System.AssertException: Assertion Failed: Expected: null, Actual: 00Q1Y00001xUtI9UAK
Stack Trace: Class.Test_AccountTriggerHandler.Account_Gets_Linked_To_Lead_Based_On_Account_Email: line 55, column 1
Class Name: Test_AccountTriggerHandler
Method Name: Account_Gets_Linked_To_Lead_Based_On_Account_ExternalReference_But_With_Different_Emails
Error Message: System.AssertException: Assertion Failed: Expected: null, Actual: 00Q1Y00001xUtIAUA0 Stack Trace: Class.Test_AccountTriggerHandler.Account_Gets_Linked_To_Lead_Based_On_Account_ExternalReference_But_With_Different_Emails: line 34, column 1
That's a great point - the sandbox I copied that from hadn't been refreshed in a while. Here is the full "AccountTriggerHandler" code from our Production instance:
For Code Line 34 (Lines 28 - 34): A Test Generator class called "CreateTestData" was used to generate a test account record. I think the method used within this test class isn't generating the accounts properly which is causing all these other failures to occurs. Sorry to both you again but can you copy and paste the code within that class here as well. I ask because it is importantly for me to understand the logic of these methods when they are being called.
It's no bother at all - thank you for noticing that. Here is the "CreateTestData" class:
Please feel free to let me know if you need anything else.
Line 55: Same issue as above but has a few more errors which needs to be corrected:
Please replace lines 44-46 in "Test_AccountTriggerHandler" with the following code:
Please replace lines 52-55 in "Test_AccountTriggerHandler" with the following code:
The changes I recommended above should resolve the two errors that were being thrown. Please inform me the outcome when you get a chance.
Thank you for your help thus far. I deployed AccountTrigger (as inactive), AccountTriggerHandler, CreateTestData, and Test_AccountTriggerHandler (with your corrections) in a change set and received one new error on line 61 of Test_AccountTriggerHandler.
Class Name: Test_AccountTriggerHandler
Method Name: Account_Gets_Linked_To_Lead_Based_On_Account_Email
Error Message: System.ListException: List index out of bounds: 0
Stack Trace: Class.Test_AccountTriggerHandler.Account_Gets_Linked_To_Lead_Based_On_Account_Email: line 61, column 1
Here is the updated Test_AccountTriggerHandler, for reference: Please let me know if I can provide any other information and thank you, again, in advance.
I noticed when you pasted the code to replace lines 44-46 that you accidentally also replaced line 43. Please the following code above line 44 and see if this resolves the issue that you are experiencing.
Class Name: Test_AccountTriggerHandler
Method Name: Account_Gets_Linked_To_Lead_Based_On_Account_Email
Error Message: System.AssertException: Assertion Failed: Expected: null, Actual: 0011Y000035xFBxQAM
Stack Trace: Class.Test_AccountTriggerHandler.Account_Gets_Linked_To_Lead_Based_On_Account_Email: line 61, column 1
Updated Test_AccountTriggerHandler:
Please replace code line 61 with the following: The fix above is a temporary work around to the issue you are having. In future scope, whoever created this trigger should review the code and try to optimize it if it is still in use. The Test Generator class should also be reviewed. I have seen many inconsistencies and violation of various best practices which is why I am recommending this.
Thank you for that fix - the error on code line 61 is resolved. The only remaining issue is that code coverage is still stuck at 65%. This is a legacy trigger that was created by a consulting firm (and, as you expertly pointed out, its work was not vetted for following best practices). Do you have any additions that would at least elevate the code coverage to 75%?
If, however, you want the trigger to appear as inactive in Production then you would first need to deactivate it in the sandbox you are deploying from and then add it to the change set. I believe the code would still need to have a 75% overall test coverage through.
Yes, that is correct. This trigger no longer needs to be active in Production. However, when I comment out the trigger's code and send it to Production as the only component in a change set I get the same code line errors as before (lines 55 and 34 of Test_AccountTriggerHandler, which were fixed in the sandbox) and the code coverage error. I think increasing the overall test coverage to at least 75% will fix this issue, but I'm unsure how to do that.
1). Open Developer Console:
2). Click on the "Test" tab and then click, "New Run"
3). Choose "Test_AccountTriggerHandler" test class from the catalogue on the left side. In the middle column, you will see a grey box next to "Name". Click on it and ensure all checkboxes below it are checked. Finally, click on the "Run" button.
4). After the testing executes, click on the "Test" tab and on the bottom right, you'll see a section called "Overall Code Coverage"
5). Click on the "AccountTriggerHandler" class. When it opens, you will see that some code is outlined in grey-blue color while others are outlined in red. The lines of code outlined in red are the ones we need to add additional test coverage to. Please provide a screenshot of some of the code that is marked in red. Below is an example of what you see:
Here is the class' code:
Line 26:
And Lines 91 & 95:
Thank you,
Michael
In order to deploy to Production, the overall test code coverage needs to be above 75% and none of the Apex test class could fail. We fixed half of the problem by addressing all those exception errors. Now we have to figure out what other code needs additional test code coverage to bring the overall percentage above 75%.
If it is more convenient for you, I can provide you my email and schedule a Zoom meeting to further troubleshoot this together. I know we've been chatting back and forth for awhile so I just wanted to give you this option if you want a quicker fix.
Thanks again for understanding and I look forward to hearing back from you soon!