function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
MarkLevyMarkLevy 

Code Coverage for Lead Insertion Trigger

I'm trying to create a new trigger before Lead insertion to check for duplicates from Leads or Contacts and prevent insertion. The duplicate check I'm going for is checking if newLeadEmail = existingEmail or if newLeadEmail = existingAltEmail (etc etc) basically preventing duplicates being added if alt email or email exists anywhere between the email or altEmail fields.

I'm getting a 71% code coverage unfortunately and really don't know how to go about making a test case cover more. I've created a test case that checks over some very basic insertion of Leads but it isn't covering my code.

Here are the lines for Lead checking that are not covered (similar lines for contact checking are also not covered):
*existingLeadList queries the database for existing leads that have Email or Alt Email matches
for(Lead newLead : Trigger.new){
                for(Lead exisitingLead : existingLeadList ){
                    if((newLead.Email == exisitingLead.Email)||(newLead.Alt_Email__c == exisitingLead.Alt_Email__c)||(newLead.Email==exisitingLead.Alt_Email__c)||(newLead.Alt_Email__c == exisitingLead.Email)){
                        newLead.addError('Duplicate Lead');
                    }
                }
            }

Any ideas on how to make a test case for this? Is there something I'm missing? Shouldn't basic Lead insertion test cases work for this?

Also as a side question: when I add the checking for alt email in my test for inserting duplicate leads it fails (naturally) because this trigger isn't in place yet to make it succeed at failing to insert a duplicate based on newEmail = oldAltEmail, but I shouldn't be publishing a test that fails should I? How do I deploy my trigger if the test I create to test it fails unless the trigger is active?

Any help here is appreciated. I'm a bit stuck at the moment. Thanks!
Best Answer chosen by MarkLevy
Sean McMickle 10Sean McMickle 10

All tests relating to insertion of lead will be testing your trigger. That's how it should be. It's testing the system as one, as opposed to individual pieces. If all pieces worked on their own, but none of them worked together, and tests only tested individual pieces, we would never know from unit testing that the project would fail.

Anyways, in your trigger code, you are testing email duplicates, so I would propose something like this ::

Lead testEmailLead = new Lead();
testEmailLead.email = 'testEmail@test.com';
(insert other required fields after this one)
insert testEmailLead;

Lead testDuplicateEmailLead = new Lead();
testDuplicateEmailLead = 'testEmail@test.com';
(insert other required fields after this one)
insert testDuplicateEmailLead;


This will give you the code coverage you need, however, don't forget to actually test to see if the lead is there or not.  If you need help with that, let me know.

There are also some problems with your base code, for example, what if someone writes Testemail@test.com, then they write testEmail@test.com. Those would techincally be the same email addresses, but your code would allow it to happen. 

Also, don't forget, you can insert more than one record at a time via data loader. In that case, you would be able to insert many leads at the same time with the same email, since your code compares trigger.new to already existing leads. The leads will be inserted 200 at a time. If more than one of those 200 had the same email, it would bypass your code.

All Answers

Sean McMickle 10Sean McMickle 10
What's the code above that? How do you get existing leads? If there are no existing leads, you wouldn't have coverage here. 
MarkLevyMarkLevy
Existing leads are populated by a select statement.
 
String queryString = 'select Email, Alt_Email__c from Lead where Email IN : emailSet OR Alt_Email__c IN : emailSet';
        
        if(altEmailSet.size() > 0){
            queryString = queryString + ' OR Alt_Email__c IN : altEmailSet OR Email IN : altEmailSet ';
        }

//List to store records that matches the criteria
        List<Lead> existingLeadList = new List<Lead>();
        
        //Get the existing records that matches the criteria
        existingLeadList = database.query(queryString);

And the original code I posted is under a check for whethero r not the existingLeadList has a size > 0:
 
//Check whether any duplicated are there
        //If present show error
        if(existingLeadList.size() > 0){
       for(Lead exisitingLead : existingLeadList ){
                    if((newLead.Email == exisitingLead.Email)||(newLead.Alt_Email__c == exisitingLead.Alt_Email__c)||(newLead.Email==exisitingLead.Alt_Email__c)||(newLead.Alt_Email__c == exisitingLead.Email)){
                        newLead.addError('Duplicate Lead');
                    }
                }
}

Why would there be no code coverage without existing leads?
Sean McMickle 10Sean McMickle 10
It will not be able to iterate through the loop if there are no existing leads. 

Try putting a debug statement to check if there are any existing leads.
MarkLevyMarkLevy
I don't understand. Is it a requirement that there be existing leads? This is code in my trigger not in my test case, and there should definitely be the possibility that there aren't existing leads in the trigger, that's the very possibility that throws the error / prevents insertion of duplicates.
Sean McMickle 10Sean McMickle 10
The original problem was that you did not have code coverage. In your test class, you must ensure that you will have existing leads, otherwise it will not cover that portion of the code.
MarkLevyMarkLevy
I'm having trouble understanding how that makes sense. There is a case logically when there wouldn't be existing leads, that's what allows the lead to be created, only if there are existing leads does the error prevent insertion because existing leads are duplicates; Without that logic this trigger wouldn't make any sense. How do I code this in another way that the test case will cover this code when there aren't existing leads?
Sean McMickle 10Sean McMickle 10
Your code here is just fine. It's the code in the test class that you need to worry about. You need to change your test class code to ensure that you have a duplicate lead. 

The entire point of the test class is to test expected cases, I.E. a case where there is no duplicate, and a case where there is a duplicate. The code portion that is not covered in your test class is the part where there are duplicates.
MarkLevyMarkLevy
Oh I see. Before I even created a test for my trigger this was being validated as 71% coverage (I presume by existing standard tests on Leads and Contacts). I then created a new test that just inserted a new lead and it was still being validated as 71% coverage. How can I tell what tests are linked to my trigger? How do I link a test specifically to my trigger and have other tests not test my trigger?

I was just doing tests like this:
 
@isTest(seeAllData=false)
private class TestLeadDuplicatePrevention {
    //code goes here, example:
    static testMethod void testBasicInsert() {
         //method code for testing basic insert here
    }
}

 
Sean McMickle 10Sean McMickle 10

All tests relating to insertion of lead will be testing your trigger. That's how it should be. It's testing the system as one, as opposed to individual pieces. If all pieces worked on their own, but none of them worked together, and tests only tested individual pieces, we would never know from unit testing that the project would fail.

Anyways, in your trigger code, you are testing email duplicates, so I would propose something like this ::

Lead testEmailLead = new Lead();
testEmailLead.email = 'testEmail@test.com';
(insert other required fields after this one)
insert testEmailLead;

Lead testDuplicateEmailLead = new Lead();
testDuplicateEmailLead = 'testEmail@test.com';
(insert other required fields after this one)
insert testDuplicateEmailLead;


This will give you the code coverage you need, however, don't forget to actually test to see if the lead is there or not.  If you need help with that, let me know.

There are also some problems with your base code, for example, what if someone writes Testemail@test.com, then they write testEmail@test.com. Those would techincally be the same email addresses, but your code would allow it to happen. 

Also, don't forget, you can insert more than one record at a time via data loader. In that case, you would be able to insert many leads at the same time with the same email, since your code compares trigger.new to already existing leads. The leads will be inserted 200 at a time. If more than one of those 200 had the same email, it would bypass your code.

This was selected as the best answer
MarkLevyMarkLevy
Thank you for your help! I think I'm on the right track now.

As far as I understand string comparisons in SOQL are case insensitive, is that incorrect? https://developer.salesforce.com/forums/?id=906F0000000B1QkIAK

 
Sean McMickle 10Sean McMickle 10
That's correct, however, if you ever insert records via bulk, all of that data will be in the trigger itself. If you were still using == without using something like .toLowerCase(), those would bypass your check.