+ Start a Discussion
andyKal10andyKal10 

Help with null pointer exception in test class

I have written a trigger that calls a class, and a test class for them. When I run the test in the ide 'apex test runner' everything seems to be fine. I get 100% coverage in my class and trigger, and no warnings or errors. When I try to deploy the code to my production org I get a null pointer exception on the insert line that is highlighted below.

 

The trigger and class are posted below too.

 

Thanks!

 

@isTest
private class LeadHandlerTest {

static testMethod void testLeadHandler() {

List<Lead> testLeads = new List<Lead>();

Contact contact = new Contact(NPD_Client_Satisfaction_Survey__c = 'Yes',
LastName = 'Test',
JobFunction__c =Admin',
Email = 'test@npd.com',
ContactType__c = 'NPDCustomer');
insert contact;

Lead lead = new Lead(Phone='1234567890',
LeadSource='Advertising',
LastName='TestJohnson',
FirstName='Test',
LeadBU__c='Automotive',
Company='Test Company',
CurrencyIsoCode='USD',
Lead_Type__c='In-Person Meeting',
Status='New Leads - Not yet working',
Rating='Z - Not Contacted - Unknown Quality',
Email='test@npd.com',
MarketingCampaign__c = 'Web-Marketing-Opt In Web Page-200807'
);
testLeads.add(lead);

Lead lead2 = new Lead(Phone='1234567890',
LeadSource='Advertising',
LastName='TestJohnson2',
FirstName='Test2',
LeadBU__c='Beauty',
Company='Test Company',
CurrencyIsoCode='CAD',
Lead_Type__c='In-Person Meeting',
Status='New Leads - Not yet working',
Rating='Z - Not Contacted - Unknown Quality',
Email='test@npd.com'
);
testLeads.add(lead2);

insert testLeads;
}
}

Trigger:

 

trigger leadAfterInsertUpdate on Lead (after insert, after update) {

if(UserInfo.getUserId() <> '00500000006z3qKAAQ'){

Map<String,String> newLeadsMap = new Map<String,String>();

for(Lead newLead : Trigger.new) {
if((null != newLead.Email) && (newLead.MarketingCampaign__c == 'Web-Marketing-Opt In Web Page-200807') && (Trigger.isInsert || newLead.Email != Trigger.oldMap.get(newLead.Id).Email)) {
if(newLeadsMap.containsKey(newLead.Email)) {
newLead.Email.addError('Another new lead is already using this email address.');
}else {
newLeadsMap.put(newLead.Email, newLead.ID);
}
}
}

leadHandler.leadDeDuper(newLeadsMap);
}

}

 Class

 

 

public with sharing class leadHandler {
	
    Public Static Void leadDeDuper(Map<String,String> newLeads) {
        Set<String> leadsToDelete = new Set<String>();
        Map<id,Lead> newLeadMap = new Map <ID, Lead>([Select Id, FirstName, LastName, Phone, PrimaryAreaOfInterest__c, Blog__c, Email, HasOptedOutOfEmail,Press_Releases__c,Insights_Newsletter__c,Product_Announcements__c,Marketing_Opt_Out__c from Lead Where ID IN: newLeads.values()]);
        List<Lead> leadsToDeleteList = new List<Lead>();
        List<Lead> existingLeads = new List<Lead>();
        List<Contact> contactsToDelete = new List<Contact>();
        List<Contact> existingContacts = new List<Contact>();
        
        //finds existing Leads where their email equals the incoming Lead
        for(Lead leadB : [select Id, FirstName, LastName,PrimaryAreaofInterest__c,Phone, Blog__c,Email,HasOptedOutofEmail,Product_Announcements__c, MarketingCampaign__c, Insights_Newsletter__c,Press_Releases__c from Lead where Email IN :newLeads.KeySet()]) {
            //adds the incoming lead to a set that will be deleted further down
            leadsToDelete.add(newLeads.get(leadB.email));   
                    
            //updates fields in existing leads
            leadB.HasOptedOutOfEmail = false;
            leadB.Press_Releases__c = newLeadMap.get(newLeads.get(leadB.email)).Press_Releases__c;
            leadB.Insights_Newsletter__c = newLeadMap.get(newLeads.get(leadB.email)).Insights_Newsletter__c;
            leadB.Product_Announcements__c = newLeadMap.get(newLeads.get(leadB.email)).Product_Announcements__c;
            leadB.Blog__c =newLeadMap.get(newLeads.get(leadB.email)).Blog__c;
            leadB.Marketing_Opt_Out__c = false;
            leadB.FirstName = newLeadMap.get(newLeads.get(leadB.email)).FirstName;
            leadB.LastName = newLeadMap.get(newLeads.get(leadB.email)).LastName;
            leadB.PrimaryAreaOfInterest__c = newLeadMap.get(newLeads.get(leadB.email)).PrimaryAreaOfInterest__c;
            leadB.Phone = newLeadMap.get(newLeads.get(leadB.email)).Phone;
           
            existingLeads.add(leadB);
        }
        
        if(existingLeads.size()>0) {
            update existingLeads;
        }
        //finds existing contacts where their email equals the incoming leads
        for(Contact contactA : [select ID, Name, Email, HasOptedOutofEmail, Insights_Newsletter__c, Press_Releases__c from Contact where Email IN :newLeads.keySet()]) {
            
            //adds the lead to a set to be deleted below
            leadsToDelete.add(newLeads.get(contactA.Email));
            
            //updates the existing contact          
            contactA.HasOptedOutOfEmail = false;
            contactA.Insights_Newsletter__c = newLeadMap.get(newLeads.get(contactA.email)).Insights_Newsletter__c;
            contactA.Press_Releases__c = newLeadMap.get(newLeads.get(contactA.email)).Press_Releases__c;
            contactA.Product_Announcements__c = newLeadMap.get(newLeads.get(contactA.email)).Product_Announcements__c;
            contactA.Blog__c = newLeadMap.get(newLeads.get(contactA.email)).Blog__c;
            contactA.FirstName = newLeadMap.get(newLeads.get(contactA.email)).FirstName;
            contactA.LastName = newLeadMap.get(newLeads.get(contactA.email)).LastName;
            contactA.Phone = newLeadMap.get(newLeads.get(contactA.email)).Phone;
            
            existingContacts.add(contactA);
        }
       
        if(existingContacts.size()>0) {
            update existingContacts;
        }
        
        if(leadsToDelete.size()>0) {
        	for(Lead dLead : [Select ID from Lead where ID IN:leadsToDelete]) {
        		leadsToDeleteList.add(dLead);
        	}
            delete leadsToDeleteList;
        }
        
    }

}

 

 

 

 

 

WesNolte__cWesNolte__c

Hey

 

Can you post more of the stack trace (the exception). It should tell you each of the lines in the test class, trigger and util class where the error occured. It'll help us track it down much quicker.

 

Wes

andyKal10andyKal10

Hey Wes,

I apologize for posting the entire Debug Log. I just got some time work on this again and discovered the Debug Log Summary, which I guess is what you were asking for, and has allowed me to get a little warmer, but still stumped.

 

This is where I am at:

 

the Debug Log Summary says the following:

 

# Test Results:

Run Failures:
  LeadHandlerTest.testLeadHandler System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, leadAfterInsertUpdate: execution of AfterInsert

caused by: System.NullPointerException: Attempt to de-reference a null object

Class.leadHandler.leadDeDuper: line 18, column 81
Trigger.leadAfterInsertUpdate: line 17, column 3: []
  Average test coverage across all Apex Classes and Triggers is 74%, at least 75% test coverage is required

 

So, l looked to line 18, which is the following:

 

leadB.Press_Releases__c = newLeadMap.get(newLeads.get(leadB.email)).Press_Releases__c;

 

 

I tried the following things:

I put a system.debug above the line:

 

system.debug('Hello World! '+newLeadMap.get(newLeads.get(leadB.email)).Press_Releases__c); 

To test what value these Map methods were actually retrieving. I expected to find null in the log, but instead everything seems to be fine. The value reads as True or False depending on what I put in the test class.

 

I then tried commenting out the line just to see if the error would drop to line 19, which is what I assumed would happen because it is the next line to use the map methods. Instead the Debug Summary pointed to line 18 again. So, now I am really confused.

 

Thanks,

Andy

 

 

 

WesNolte__cWesNolte__c

Hey 

 

One of these must be null then:

 

leadB

newLeads.get(n)

the value returned from newLeadMap

 

I would start with leadB as if you try use the line that is causing the actual exception, an exception will be thrown and the debug line won't be output. Make sense?

 

If all leadB vars are not null, then output the value of newLead.get(n).

 

Wes

andyKal10andyKal10

Hi Wes,

I didn't see what you were getting at by writing: "use the line that is causing the actual exception, an exception will be thrown and the debug line won't be output"

 

Anyway, the following is what I have tried so far.

 

After various system.debug() statements I found that the lines of code from the util class were showing up in the debug log even though the trigger sent nothing. To be more specific, my test class inserts 2 Leads. One of the leads meets the criteria of the trigger, and the other doesn't. I used system.debug()s to test for the size of the map being passed to util class, the size of the map within util class, and for values within the map. The debug log indicated that the code in the util class was being processed even for the Lead that didn't meet the criteria of the trigger. So, for the lead that meets the criteria system.debug(newLeads.isEmpty()) would return false. Then looking further down in the debug log I found the statement was returning true. So, I safegaurded against this with the following code in the trigger:

 

if(newLeadsMap.keySet().size() > 0) {
            leadHandler.leadDeDuper(newLeadsMap);
        }

 This solved that problem...the debug log no longer shows that the util class is running for both leads...but only for the one that meets the trigger's criteria.

 

However, the validation results are the same.

 

I also tested all of the fields in leadB using system.debug()s. Everything was fine. I did find a null value in one of the fields that I was querying for, which I didn't think would cause a problem, but I tried populating the field anyway, and still I got the same results in the validation.

 

I will keep trying, but perhaps my debug technique is not appropriate. I simply put system.debug()s strategically before or after lines of code that I am interested in to see what the results are when I run in the test runner.

 

Is there another approach that you could suggest?